xref: /openbmc/linux/arch/x86/kernel/dumpstack_32.c (revision b17b01533b719e9949e437abf66436a875739b40)
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  */
5*b17b0153SIngo Molnar #include <linux/sched/debug.h>
62bc5f927SAlexander van Heukelum #include <linux/kallsyms.h>
72bc5f927SAlexander van Heukelum #include <linux/kprobes.h>
82bc5f927SAlexander van Heukelum #include <linux/uaccess.h>
92bc5f927SAlexander van Heukelum #include <linux/hardirq.h>
102bc5f927SAlexander van Heukelum #include <linux/kdebug.h>
11186f4360SPaul Gortmaker #include <linux/export.h>
122bc5f927SAlexander van Heukelum #include <linux/ptrace.h>
132bc5f927SAlexander van Heukelum #include <linux/kexec.h>
14b8030906SIngo Molnar #include <linux/sysfs.h>
152bc5f927SAlexander van Heukelum #include <linux/bug.h>
162bc5f927SAlexander van Heukelum #include <linux/nmi.h>
172bc5f927SAlexander van Heukelum 
182bc5f927SAlexander van Heukelum #include <asm/stacktrace.h>
192bc5f927SAlexander van Heukelum 
203d02a9c4SJosh Poimboeuf const char *stack_type_name(enum stack_type type)
21198d208dSSteven Rostedt {
223d02a9c4SJosh Poimboeuf 	if (type == STACK_TYPE_IRQ)
233d02a9c4SJosh Poimboeuf 		return "IRQ";
243d02a9c4SJosh Poimboeuf 
253d02a9c4SJosh Poimboeuf 	if (type == STACK_TYPE_SOFTIRQ)
263d02a9c4SJosh Poimboeuf 		return "SOFTIRQ";
273d02a9c4SJosh Poimboeuf 
283d02a9c4SJosh Poimboeuf 	return NULL;
29198d208dSSteven Rostedt }
30198d208dSSteven Rostedt 
31cb76c939SJosh Poimboeuf static bool in_hardirq_stack(unsigned long *stack, struct stack_info *info)
32198d208dSSteven Rostedt {
33cb76c939SJosh Poimboeuf 	unsigned long *begin = (unsigned long *)this_cpu_read(hardirq_stack);
34cb76c939SJosh Poimboeuf 	unsigned long *end   = begin + (THREAD_SIZE / sizeof(long));
35198d208dSSteven Rostedt 
365fe599e0SJosh Poimboeuf 	/*
375fe599e0SJosh Poimboeuf 	 * This is a software stack, so 'end' can be a valid stack pointer.
385fe599e0SJosh Poimboeuf 	 * It just means the stack is empty.
395fe599e0SJosh Poimboeuf 	 */
405fe599e0SJosh Poimboeuf 	if (stack < begin || stack > end)
41cb76c939SJosh Poimboeuf 		return false;
42cb76c939SJosh Poimboeuf 
43cb76c939SJosh Poimboeuf 	info->type	= STACK_TYPE_IRQ;
44cb76c939SJosh Poimboeuf 	info->begin	= begin;
45cb76c939SJosh Poimboeuf 	info->end	= end;
46cb76c939SJosh Poimboeuf 
47cb76c939SJosh Poimboeuf 	/*
48cb76c939SJosh Poimboeuf 	 * See irq_32.c -- the next stack pointer is stored at the beginning of
49cb76c939SJosh Poimboeuf 	 * the stack.
50cb76c939SJosh Poimboeuf 	 */
51cb76c939SJosh Poimboeuf 	info->next_sp	= (unsigned long *)*begin;
52cb76c939SJosh Poimboeuf 
53cb76c939SJosh Poimboeuf 	return true;
54198d208dSSteven Rostedt }
55198d208dSSteven Rostedt 
56cb76c939SJosh Poimboeuf static bool in_softirq_stack(unsigned long *stack, struct stack_info *info)
57198d208dSSteven Rostedt {
58cb76c939SJosh Poimboeuf 	unsigned long *begin = (unsigned long *)this_cpu_read(softirq_stack);
59cb76c939SJosh Poimboeuf 	unsigned long *end   = begin + (THREAD_SIZE / sizeof(long));
60198d208dSSteven Rostedt 
615fe599e0SJosh Poimboeuf 	/*
625fe599e0SJosh Poimboeuf 	 * This is a software stack, so 'end' can be a valid stack pointer.
635fe599e0SJosh Poimboeuf 	 * It just means the stack is empty.
645fe599e0SJosh Poimboeuf 	 */
655fe599e0SJosh Poimboeuf 	if (stack < begin || stack > end)
66cb76c939SJosh Poimboeuf 		return false;
67cb76c939SJosh Poimboeuf 
68cb76c939SJosh Poimboeuf 	info->type	= STACK_TYPE_SOFTIRQ;
69cb76c939SJosh Poimboeuf 	info->begin	= begin;
70cb76c939SJosh Poimboeuf 	info->end	= end;
71cb76c939SJosh Poimboeuf 
72cb76c939SJosh Poimboeuf 	/*
73cb76c939SJosh Poimboeuf 	 * The next stack pointer is stored at the beginning of the stack.
74cb76c939SJosh Poimboeuf 	 * See irq_32.c.
75cb76c939SJosh Poimboeuf 	 */
76cb76c939SJosh Poimboeuf 	info->next_sp	= (unsigned long *)*begin;
77cb76c939SJosh Poimboeuf 
78cb76c939SJosh Poimboeuf 	return true;
79cb76c939SJosh Poimboeuf }
80cb76c939SJosh Poimboeuf 
81cb76c939SJosh Poimboeuf int get_stack_info(unsigned long *stack, struct task_struct *task,
82cb76c939SJosh Poimboeuf 		   struct stack_info *info, unsigned long *visit_mask)
83cb76c939SJosh Poimboeuf {
84cb76c939SJosh Poimboeuf 	if (!stack)
85cb76c939SJosh Poimboeuf 		goto unknown;
86cb76c939SJosh Poimboeuf 
87cb76c939SJosh Poimboeuf 	task = task ? : current;
88cb76c939SJosh Poimboeuf 
89cb76c939SJosh Poimboeuf 	if (in_task_stack(stack, task, info))
90fcd709efSJosh Poimboeuf 		goto recursion_check;
91cb76c939SJosh Poimboeuf 
92cb76c939SJosh Poimboeuf 	if (task != current)
93cb76c939SJosh Poimboeuf 		goto unknown;
94cb76c939SJosh Poimboeuf 
95cb76c939SJosh Poimboeuf 	if (in_hardirq_stack(stack, info))
96fcd709efSJosh Poimboeuf 		goto recursion_check;
97cb76c939SJosh Poimboeuf 
98cb76c939SJosh Poimboeuf 	if (in_softirq_stack(stack, info))
99fcd709efSJosh Poimboeuf 		goto recursion_check;
100fcd709efSJosh Poimboeuf 
101fcd709efSJosh Poimboeuf 	goto unknown;
102fcd709efSJosh Poimboeuf 
103fcd709efSJosh Poimboeuf recursion_check:
104fcd709efSJosh Poimboeuf 	/*
105fcd709efSJosh Poimboeuf 	 * Make sure we don't iterate through any given stack more than once.
106fcd709efSJosh Poimboeuf 	 * If it comes up a second time then there's something wrong going on:
107fcd709efSJosh Poimboeuf 	 * just break out and report an unknown stack type.
108fcd709efSJosh Poimboeuf 	 */
109fcd709efSJosh Poimboeuf 	if (visit_mask) {
1100d2b8579SJosh Poimboeuf 		if (*visit_mask & (1UL << info->type)) {
1110d2b8579SJosh Poimboeuf 			printk_deferred_once(KERN_WARNING "WARNING: stack recursion on stack type %d\n", info->type);
112fcd709efSJosh Poimboeuf 			goto unknown;
1130d2b8579SJosh Poimboeuf 		}
114fcd709efSJosh Poimboeuf 		*visit_mask |= 1UL << info->type;
115fcd709efSJosh Poimboeuf 	}
116fcd709efSJosh Poimboeuf 
117cb76c939SJosh Poimboeuf 	return 0;
118cb76c939SJosh Poimboeuf 
119cb76c939SJosh Poimboeuf unknown:
120cb76c939SJosh Poimboeuf 	info->type = STACK_TYPE_UNKNOWN;
121cb76c939SJosh Poimboeuf 	return -EINVAL;
122198d208dSSteven Rostedt }
1230406ca6dSFrederic Weisbecker 
12457da8b96SJan Beulich void show_regs(struct pt_regs *regs)
1252bc5f927SAlexander van Heukelum {
1262bc5f927SAlexander van Heukelum 	int i;
1272bc5f927SAlexander van Heukelum 
128a43cb95dSTejun Heo 	show_regs_print_info(KERN_EMERG);
129f39b6f0eSAndy Lutomirski 	__show_regs(regs, !user_mode(regs));
1302bc5f927SAlexander van Heukelum 
1312bc5f927SAlexander van Heukelum 	/*
1322bc5f927SAlexander van Heukelum 	 * When in-kernel, we also print out the stack and code at the
1332bc5f927SAlexander van Heukelum 	 * time of the fault..
1342bc5f927SAlexander van Heukelum 	 */
135f39b6f0eSAndy Lutomirski 	if (!user_mode(regs)) {
1362bc5f927SAlexander van Heukelum 		unsigned int code_prologue = code_bytes * 43 / 64;
1372bc5f927SAlexander van Heukelum 		unsigned int code_len = code_bytes;
1382bc5f927SAlexander van Heukelum 		unsigned char c;
1392bc5f927SAlexander van Heukelum 		u8 *ip;
1402bc5f927SAlexander van Heukelum 
1410ee1dd9fSJosh Poimboeuf 		show_trace_log_lvl(current, regs, NULL, KERN_EMERG);
1422bc5f927SAlexander van Heukelum 
143c767a54bSJoe Perches 		pr_emerg("Code:");
1442bc5f927SAlexander van Heukelum 
1452bc5f927SAlexander van Heukelum 		ip = (u8 *)regs->ip - code_prologue;
1462bc5f927SAlexander van Heukelum 		if (ip < (u8 *)PAGE_OFFSET || probe_kernel_address(ip, c)) {
1478a541665SAlexander van Heukelum 			/* try starting at IP */
1482bc5f927SAlexander van Heukelum 			ip = (u8 *)regs->ip;
1492bc5f927SAlexander van Heukelum 			code_len = code_len - code_prologue + 1;
1502bc5f927SAlexander van Heukelum 		}
1512bc5f927SAlexander van Heukelum 		for (i = 0; i < code_len; i++, ip++) {
1522bc5f927SAlexander van Heukelum 			if (ip < (u8 *)PAGE_OFFSET ||
1532bc5f927SAlexander van Heukelum 					probe_kernel_address(ip, c)) {
154c767a54bSJoe Perches 				pr_cont("  Bad EIP value.");
1552bc5f927SAlexander van Heukelum 				break;
1562bc5f927SAlexander van Heukelum 			}
1572bc5f927SAlexander van Heukelum 			if (ip == (u8 *)regs->ip)
158c767a54bSJoe Perches 				pr_cont(" <%02x>", c);
1592bc5f927SAlexander van Heukelum 			else
160c767a54bSJoe Perches 				pr_cont(" %02x", c);
1612bc5f927SAlexander van Heukelum 		}
1622bc5f927SAlexander van Heukelum 	}
163c767a54bSJoe Perches 	pr_cont("\n");
1642bc5f927SAlexander van Heukelum }
1652bc5f927SAlexander van Heukelum 
1662bc5f927SAlexander van Heukelum int is_valid_bugaddr(unsigned long ip)
1672bc5f927SAlexander van Heukelum {
1682bc5f927SAlexander van Heukelum 	unsigned short ud2;
1692bc5f927SAlexander van Heukelum 
1702bc5f927SAlexander van Heukelum 	if (ip < PAGE_OFFSET)
1712bc5f927SAlexander van Heukelum 		return 0;
1722bc5f927SAlexander van Heukelum 	if (probe_kernel_address((unsigned short *)ip, ud2))
1732bc5f927SAlexander van Heukelum 		return 0;
1742bc5f927SAlexander van Heukelum 
1752bc5f927SAlexander van Heukelum 	return ud2 == 0x0b0f;
1762bc5f927SAlexander van Heukelum }
177