xref: /openbmc/linux/arch/x86/kernel/dumpstack_32.c (revision b24413180f5600bcb3bb70fbed5cf186b60864bd)
1*b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
22bc5f927SAlexander van Heukelum /*
32bc5f927SAlexander van Heukelum  *  Copyright (C) 1991, 1992  Linus Torvalds
42bc5f927SAlexander van Heukelum  *  Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs
52bc5f927SAlexander van Heukelum  */
6b17b0153SIngo Molnar #include <linux/sched/debug.h>
72bc5f927SAlexander van Heukelum #include <linux/kallsyms.h>
82bc5f927SAlexander van Heukelum #include <linux/kprobes.h>
92bc5f927SAlexander van Heukelum #include <linux/uaccess.h>
102bc5f927SAlexander van Heukelum #include <linux/hardirq.h>
112bc5f927SAlexander van Heukelum #include <linux/kdebug.h>
12186f4360SPaul Gortmaker #include <linux/export.h>
132bc5f927SAlexander van Heukelum #include <linux/ptrace.h>
142bc5f927SAlexander van Heukelum #include <linux/kexec.h>
15b8030906SIngo Molnar #include <linux/sysfs.h>
162bc5f927SAlexander van Heukelum #include <linux/bug.h>
172bc5f927SAlexander van Heukelum #include <linux/nmi.h>
182bc5f927SAlexander van Heukelum 
192bc5f927SAlexander van Heukelum #include <asm/stacktrace.h>
202bc5f927SAlexander van Heukelum 
213d02a9c4SJosh Poimboeuf const char *stack_type_name(enum stack_type type)
22198d208dSSteven Rostedt {
233d02a9c4SJosh Poimboeuf 	if (type == STACK_TYPE_IRQ)
243d02a9c4SJosh Poimboeuf 		return "IRQ";
253d02a9c4SJosh Poimboeuf 
263d02a9c4SJosh Poimboeuf 	if (type == STACK_TYPE_SOFTIRQ)
273d02a9c4SJosh Poimboeuf 		return "SOFTIRQ";
283d02a9c4SJosh Poimboeuf 
293d02a9c4SJosh Poimboeuf 	return NULL;
30198d208dSSteven Rostedt }
31198d208dSSteven Rostedt 
32cb76c939SJosh Poimboeuf static bool in_hardirq_stack(unsigned long *stack, struct stack_info *info)
33198d208dSSteven Rostedt {
34cb76c939SJosh Poimboeuf 	unsigned long *begin = (unsigned long *)this_cpu_read(hardirq_stack);
35cb76c939SJosh Poimboeuf 	unsigned long *end   = begin + (THREAD_SIZE / sizeof(long));
36198d208dSSteven Rostedt 
375fe599e0SJosh Poimboeuf 	/*
385fe599e0SJosh Poimboeuf 	 * This is a software stack, so 'end' can be a valid stack pointer.
395fe599e0SJosh Poimboeuf 	 * It just means the stack is empty.
405fe599e0SJosh Poimboeuf 	 */
415a3cf869SJosh Poimboeuf 	if (stack <= begin || stack > end)
42cb76c939SJosh Poimboeuf 		return false;
43cb76c939SJosh Poimboeuf 
44cb76c939SJosh Poimboeuf 	info->type	= STACK_TYPE_IRQ;
45cb76c939SJosh Poimboeuf 	info->begin	= begin;
46cb76c939SJosh Poimboeuf 	info->end	= end;
47cb76c939SJosh Poimboeuf 
48cb76c939SJosh Poimboeuf 	/*
49cb76c939SJosh Poimboeuf 	 * See irq_32.c -- the next stack pointer is stored at the beginning of
50cb76c939SJosh Poimboeuf 	 * the stack.
51cb76c939SJosh Poimboeuf 	 */
52cb76c939SJosh Poimboeuf 	info->next_sp	= (unsigned long *)*begin;
53cb76c939SJosh Poimboeuf 
54cb76c939SJosh Poimboeuf 	return true;
55198d208dSSteven Rostedt }
56198d208dSSteven Rostedt 
57cb76c939SJosh Poimboeuf static bool in_softirq_stack(unsigned long *stack, struct stack_info *info)
58198d208dSSteven Rostedt {
59cb76c939SJosh Poimboeuf 	unsigned long *begin = (unsigned long *)this_cpu_read(softirq_stack);
60cb76c939SJosh Poimboeuf 	unsigned long *end   = begin + (THREAD_SIZE / sizeof(long));
61198d208dSSteven Rostedt 
625fe599e0SJosh Poimboeuf 	/*
635fe599e0SJosh Poimboeuf 	 * This is a software stack, so 'end' can be a valid stack pointer.
645fe599e0SJosh Poimboeuf 	 * It just means the stack is empty.
655fe599e0SJosh Poimboeuf 	 */
665a3cf869SJosh Poimboeuf 	if (stack <= begin || stack > end)
67cb76c939SJosh Poimboeuf 		return false;
68cb76c939SJosh Poimboeuf 
69cb76c939SJosh Poimboeuf 	info->type	= STACK_TYPE_SOFTIRQ;
70cb76c939SJosh Poimboeuf 	info->begin	= begin;
71cb76c939SJosh Poimboeuf 	info->end	= end;
72cb76c939SJosh Poimboeuf 
73cb76c939SJosh Poimboeuf 	/*
74cb76c939SJosh Poimboeuf 	 * The next stack pointer is stored at the beginning of the stack.
75cb76c939SJosh Poimboeuf 	 * See irq_32.c.
76cb76c939SJosh Poimboeuf 	 */
77cb76c939SJosh Poimboeuf 	info->next_sp	= (unsigned long *)*begin;
78cb76c939SJosh Poimboeuf 
79cb76c939SJosh Poimboeuf 	return true;
80cb76c939SJosh Poimboeuf }
81cb76c939SJosh Poimboeuf 
82cb76c939SJosh Poimboeuf int get_stack_info(unsigned long *stack, struct task_struct *task,
83cb76c939SJosh Poimboeuf 		   struct stack_info *info, unsigned long *visit_mask)
84cb76c939SJosh Poimboeuf {
85cb76c939SJosh Poimboeuf 	if (!stack)
86cb76c939SJosh Poimboeuf 		goto unknown;
87cb76c939SJosh Poimboeuf 
88cb76c939SJosh Poimboeuf 	task = task ? : current;
89cb76c939SJosh Poimboeuf 
90cb76c939SJosh Poimboeuf 	if (in_task_stack(stack, task, info))
91fcd709efSJosh Poimboeuf 		goto recursion_check;
92cb76c939SJosh Poimboeuf 
93cb76c939SJosh Poimboeuf 	if (task != current)
94cb76c939SJosh Poimboeuf 		goto unknown;
95cb76c939SJosh Poimboeuf 
96cb76c939SJosh Poimboeuf 	if (in_hardirq_stack(stack, info))
97fcd709efSJosh Poimboeuf 		goto recursion_check;
98cb76c939SJosh Poimboeuf 
99cb76c939SJosh Poimboeuf 	if (in_softirq_stack(stack, info))
100fcd709efSJosh Poimboeuf 		goto recursion_check;
101fcd709efSJosh Poimboeuf 
102fcd709efSJosh Poimboeuf 	goto unknown;
103fcd709efSJosh Poimboeuf 
104fcd709efSJosh Poimboeuf recursion_check:
105fcd709efSJosh Poimboeuf 	/*
106fcd709efSJosh Poimboeuf 	 * Make sure we don't iterate through any given stack more than once.
107fcd709efSJosh Poimboeuf 	 * If it comes up a second time then there's something wrong going on:
108fcd709efSJosh Poimboeuf 	 * just break out and report an unknown stack type.
109fcd709efSJosh Poimboeuf 	 */
110fcd709efSJosh Poimboeuf 	if (visit_mask) {
1110d2b8579SJosh Poimboeuf 		if (*visit_mask & (1UL << info->type)) {
1120d2b8579SJosh Poimboeuf 			printk_deferred_once(KERN_WARNING "WARNING: stack recursion on stack type %d\n", info->type);
113fcd709efSJosh Poimboeuf 			goto unknown;
1140d2b8579SJosh Poimboeuf 		}
115fcd709efSJosh Poimboeuf 		*visit_mask |= 1UL << info->type;
116fcd709efSJosh Poimboeuf 	}
117fcd709efSJosh Poimboeuf 
118cb76c939SJosh Poimboeuf 	return 0;
119cb76c939SJosh Poimboeuf 
120cb76c939SJosh Poimboeuf unknown:
121cb76c939SJosh Poimboeuf 	info->type = STACK_TYPE_UNKNOWN;
122cb76c939SJosh Poimboeuf 	return -EINVAL;
123198d208dSSteven Rostedt }
1240406ca6dSFrederic Weisbecker 
12557da8b96SJan Beulich void show_regs(struct pt_regs *regs)
1262bc5f927SAlexander van Heukelum {
1272bc5f927SAlexander van Heukelum 	int i;
1282bc5f927SAlexander van Heukelum 
129a43cb95dSTejun Heo 	show_regs_print_info(KERN_EMERG);
130f39b6f0eSAndy Lutomirski 	__show_regs(regs, !user_mode(regs));
1312bc5f927SAlexander van Heukelum 
1322bc5f927SAlexander van Heukelum 	/*
1332bc5f927SAlexander van Heukelum 	 * When in-kernel, we also print out the stack and code at the
1342bc5f927SAlexander van Heukelum 	 * time of the fault..
1352bc5f927SAlexander van Heukelum 	 */
136f39b6f0eSAndy Lutomirski 	if (!user_mode(regs)) {
1372bc5f927SAlexander van Heukelum 		unsigned int code_prologue = code_bytes * 43 / 64;
1382bc5f927SAlexander van Heukelum 		unsigned int code_len = code_bytes;
1392bc5f927SAlexander van Heukelum 		unsigned char c;
1402bc5f927SAlexander van Heukelum 		u8 *ip;
1412bc5f927SAlexander van Heukelum 
1420ee1dd9fSJosh Poimboeuf 		show_trace_log_lvl(current, regs, NULL, KERN_EMERG);
1432bc5f927SAlexander van Heukelum 
144c767a54bSJoe Perches 		pr_emerg("Code:");
1452bc5f927SAlexander van Heukelum 
1462bc5f927SAlexander van Heukelum 		ip = (u8 *)regs->ip - code_prologue;
1472bc5f927SAlexander van Heukelum 		if (ip < (u8 *)PAGE_OFFSET || probe_kernel_address(ip, c)) {
1488a541665SAlexander van Heukelum 			/* try starting at IP */
1492bc5f927SAlexander van Heukelum 			ip = (u8 *)regs->ip;
1502bc5f927SAlexander van Heukelum 			code_len = code_len - code_prologue + 1;
1512bc5f927SAlexander van Heukelum 		}
1522bc5f927SAlexander van Heukelum 		for (i = 0; i < code_len; i++, ip++) {
1532bc5f927SAlexander van Heukelum 			if (ip < (u8 *)PAGE_OFFSET ||
1542bc5f927SAlexander van Heukelum 					probe_kernel_address(ip, c)) {
155c767a54bSJoe Perches 				pr_cont("  Bad EIP value.");
1562bc5f927SAlexander van Heukelum 				break;
1572bc5f927SAlexander van Heukelum 			}
1582bc5f927SAlexander van Heukelum 			if (ip == (u8 *)regs->ip)
159c767a54bSJoe Perches 				pr_cont(" <%02x>", c);
1602bc5f927SAlexander van Heukelum 			else
161c767a54bSJoe Perches 				pr_cont(" %02x", c);
1622bc5f927SAlexander van Heukelum 		}
1632bc5f927SAlexander van Heukelum 	}
164c767a54bSJoe Perches 	pr_cont("\n");
1652bc5f927SAlexander van Heukelum }
166