xref: /openbmc/linux/arch/x86/kernel/dumpstack_32.c (revision fa33215422fd415a07ec2a00e9f1acdaf0fa8e94)
1b2441318SGreg 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 
294fe2d8b1SDave Hansen 	if (type == STACK_TYPE_ENTRY)
304fe2d8b1SDave Hansen 		return "ENTRY_TRAMPOLINE";
3133a2f1a6SAndy Lutomirski 
323d02a9c4SJosh Poimboeuf 	return NULL;
33198d208dSSteven Rostedt }
34198d208dSSteven Rostedt 
35cb76c939SJosh Poimboeuf static bool in_hardirq_stack(unsigned long *stack, struct stack_info *info)
36198d208dSSteven Rostedt {
37cb76c939SJosh Poimboeuf 	unsigned long *begin = (unsigned long *)this_cpu_read(hardirq_stack);
38cb76c939SJosh Poimboeuf 	unsigned long *end   = begin + (THREAD_SIZE / sizeof(long));
39198d208dSSteven Rostedt 
405fe599e0SJosh Poimboeuf 	/*
415fe599e0SJosh Poimboeuf 	 * This is a software stack, so 'end' can be a valid stack pointer.
425fe599e0SJosh Poimboeuf 	 * It just means the stack is empty.
435fe599e0SJosh Poimboeuf 	 */
44*fa332154SAndy Lutomirski 	if (stack < begin || stack > end)
45cb76c939SJosh Poimboeuf 		return false;
46cb76c939SJosh Poimboeuf 
47cb76c939SJosh Poimboeuf 	info->type	= STACK_TYPE_IRQ;
48cb76c939SJosh Poimboeuf 	info->begin	= begin;
49cb76c939SJosh Poimboeuf 	info->end	= end;
50cb76c939SJosh Poimboeuf 
51cb76c939SJosh Poimboeuf 	/*
52cb76c939SJosh Poimboeuf 	 * See irq_32.c -- the next stack pointer is stored at the beginning of
53cb76c939SJosh Poimboeuf 	 * the stack.
54cb76c939SJosh Poimboeuf 	 */
55cb76c939SJosh Poimboeuf 	info->next_sp	= (unsigned long *)*begin;
56cb76c939SJosh Poimboeuf 
57cb76c939SJosh Poimboeuf 	return true;
58198d208dSSteven Rostedt }
59198d208dSSteven Rostedt 
60cb76c939SJosh Poimboeuf static bool in_softirq_stack(unsigned long *stack, struct stack_info *info)
61198d208dSSteven Rostedt {
62cb76c939SJosh Poimboeuf 	unsigned long *begin = (unsigned long *)this_cpu_read(softirq_stack);
63cb76c939SJosh Poimboeuf 	unsigned long *end   = begin + (THREAD_SIZE / sizeof(long));
64198d208dSSteven Rostedt 
655fe599e0SJosh Poimboeuf 	/*
665fe599e0SJosh Poimboeuf 	 * This is a software stack, so 'end' can be a valid stack pointer.
675fe599e0SJosh Poimboeuf 	 * It just means the stack is empty.
685fe599e0SJosh Poimboeuf 	 */
69*fa332154SAndy Lutomirski 	if (stack < begin || stack > end)
70cb76c939SJosh Poimboeuf 		return false;
71cb76c939SJosh Poimboeuf 
72cb76c939SJosh Poimboeuf 	info->type	= STACK_TYPE_SOFTIRQ;
73cb76c939SJosh Poimboeuf 	info->begin	= begin;
74cb76c939SJosh Poimboeuf 	info->end	= end;
75cb76c939SJosh Poimboeuf 
76cb76c939SJosh Poimboeuf 	/*
77cb76c939SJosh Poimboeuf 	 * The next stack pointer is stored at the beginning of the stack.
78cb76c939SJosh Poimboeuf 	 * See irq_32.c.
79cb76c939SJosh Poimboeuf 	 */
80cb76c939SJosh Poimboeuf 	info->next_sp	= (unsigned long *)*begin;
81cb76c939SJosh Poimboeuf 
82cb76c939SJosh Poimboeuf 	return true;
83cb76c939SJosh Poimboeuf }
84cb76c939SJosh Poimboeuf 
85cb76c939SJosh Poimboeuf int get_stack_info(unsigned long *stack, struct task_struct *task,
86cb76c939SJosh Poimboeuf 		   struct stack_info *info, unsigned long *visit_mask)
87cb76c939SJosh Poimboeuf {
88cb76c939SJosh Poimboeuf 	if (!stack)
89cb76c939SJosh Poimboeuf 		goto unknown;
90cb76c939SJosh Poimboeuf 
91cb76c939SJosh Poimboeuf 	task = task ? : current;
92cb76c939SJosh Poimboeuf 
93cb76c939SJosh Poimboeuf 	if (in_task_stack(stack, task, info))
94fcd709efSJosh Poimboeuf 		goto recursion_check;
95cb76c939SJosh Poimboeuf 
96cb76c939SJosh Poimboeuf 	if (task != current)
97cb76c939SJosh Poimboeuf 		goto unknown;
98cb76c939SJosh Poimboeuf 
994fe2d8b1SDave Hansen 	if (in_entry_stack(stack, info))
10033a2f1a6SAndy Lutomirski 		goto recursion_check;
10133a2f1a6SAndy Lutomirski 
102cb76c939SJosh Poimboeuf 	if (in_hardirq_stack(stack, info))
103fcd709efSJosh Poimboeuf 		goto recursion_check;
104cb76c939SJosh Poimboeuf 
105cb76c939SJosh Poimboeuf 	if (in_softirq_stack(stack, info))
106fcd709efSJosh Poimboeuf 		goto recursion_check;
107fcd709efSJosh Poimboeuf 
108fcd709efSJosh Poimboeuf 	goto unknown;
109fcd709efSJosh Poimboeuf 
110fcd709efSJosh Poimboeuf recursion_check:
111fcd709efSJosh Poimboeuf 	/*
112fcd709efSJosh Poimboeuf 	 * Make sure we don't iterate through any given stack more than once.
113fcd709efSJosh Poimboeuf 	 * If it comes up a second time then there's something wrong going on:
114fcd709efSJosh Poimboeuf 	 * just break out and report an unknown stack type.
115fcd709efSJosh Poimboeuf 	 */
116fcd709efSJosh Poimboeuf 	if (visit_mask) {
1170d2b8579SJosh Poimboeuf 		if (*visit_mask & (1UL << info->type)) {
1180d2b8579SJosh Poimboeuf 			printk_deferred_once(KERN_WARNING "WARNING: stack recursion on stack type %d\n", info->type);
119fcd709efSJosh Poimboeuf 			goto unknown;
1200d2b8579SJosh Poimboeuf 		}
121fcd709efSJosh Poimboeuf 		*visit_mask |= 1UL << info->type;
122fcd709efSJosh Poimboeuf 	}
123fcd709efSJosh Poimboeuf 
124cb76c939SJosh Poimboeuf 	return 0;
125cb76c939SJosh Poimboeuf 
126cb76c939SJosh Poimboeuf unknown:
127cb76c939SJosh Poimboeuf 	info->type = STACK_TYPE_UNKNOWN;
128cb76c939SJosh Poimboeuf 	return -EINVAL;
129198d208dSSteven Rostedt }
130