xref: /linux/arch/x86/kernel/dumpstack_32.c (revision dc4e0021b00b5a4ecba56fae509217776592b0aa)
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 
32*dc4e0021SAndy Lutomirski 	if (type == STACK_TYPE_EXCEPTION)
33*dc4e0021SAndy Lutomirski 		return "#DF";
34*dc4e0021SAndy Lutomirski 
353d02a9c4SJosh Poimboeuf 	return NULL;
36198d208dSSteven Rostedt }
37198d208dSSteven Rostedt 
38cb76c939SJosh Poimboeuf static bool in_hardirq_stack(unsigned long *stack, struct stack_info *info)
39198d208dSSteven Rostedt {
40a754fe2bSThomas Gleixner 	unsigned long *begin = (unsigned long *)this_cpu_read(hardirq_stack_ptr);
41cb76c939SJosh Poimboeuf 	unsigned long *end   = begin + (THREAD_SIZE / sizeof(long));
42198d208dSSteven Rostedt 
435fe599e0SJosh Poimboeuf 	/*
445fe599e0SJosh Poimboeuf 	 * This is a software stack, so 'end' can be a valid stack pointer.
455fe599e0SJosh Poimboeuf 	 * It just means the stack is empty.
465fe599e0SJosh Poimboeuf 	 */
47fa332154SAndy Lutomirski 	if (stack < begin || stack > end)
48cb76c939SJosh Poimboeuf 		return false;
49cb76c939SJosh Poimboeuf 
50cb76c939SJosh Poimboeuf 	info->type	= STACK_TYPE_IRQ;
51cb76c939SJosh Poimboeuf 	info->begin	= begin;
52cb76c939SJosh Poimboeuf 	info->end	= end;
53cb76c939SJosh Poimboeuf 
54cb76c939SJosh Poimboeuf 	/*
55cb76c939SJosh Poimboeuf 	 * See irq_32.c -- the next stack pointer is stored at the beginning of
56cb76c939SJosh Poimboeuf 	 * the stack.
57cb76c939SJosh Poimboeuf 	 */
58cb76c939SJosh Poimboeuf 	info->next_sp	= (unsigned long *)*begin;
59cb76c939SJosh Poimboeuf 
60cb76c939SJosh Poimboeuf 	return true;
61198d208dSSteven Rostedt }
62198d208dSSteven Rostedt 
63cb76c939SJosh Poimboeuf static bool in_softirq_stack(unsigned long *stack, struct stack_info *info)
64198d208dSSteven Rostedt {
65a754fe2bSThomas Gleixner 	unsigned long *begin = (unsigned long *)this_cpu_read(softirq_stack_ptr);
66cb76c939SJosh Poimboeuf 	unsigned long *end   = begin + (THREAD_SIZE / sizeof(long));
67198d208dSSteven Rostedt 
685fe599e0SJosh Poimboeuf 	/*
695fe599e0SJosh Poimboeuf 	 * This is a software stack, so 'end' can be a valid stack pointer.
705fe599e0SJosh Poimboeuf 	 * It just means the stack is empty.
715fe599e0SJosh Poimboeuf 	 */
72fa332154SAndy Lutomirski 	if (stack < begin || stack > end)
73cb76c939SJosh Poimboeuf 		return false;
74cb76c939SJosh Poimboeuf 
75cb76c939SJosh Poimboeuf 	info->type	= STACK_TYPE_SOFTIRQ;
76cb76c939SJosh Poimboeuf 	info->begin	= begin;
77cb76c939SJosh Poimboeuf 	info->end	= end;
78cb76c939SJosh Poimboeuf 
79cb76c939SJosh Poimboeuf 	/*
80cb76c939SJosh Poimboeuf 	 * The next stack pointer is stored at the beginning of the stack.
81cb76c939SJosh Poimboeuf 	 * See irq_32.c.
82cb76c939SJosh Poimboeuf 	 */
83cb76c939SJosh Poimboeuf 	info->next_sp	= (unsigned long *)*begin;
84cb76c939SJosh Poimboeuf 
85cb76c939SJosh Poimboeuf 	return true;
86cb76c939SJosh Poimboeuf }
87cb76c939SJosh Poimboeuf 
88*dc4e0021SAndy Lutomirski static bool in_doublefault_stack(unsigned long *stack, struct stack_info *info)
89*dc4e0021SAndy Lutomirski {
90*dc4e0021SAndy Lutomirski #ifdef CONFIG_DOUBLEFAULT
91*dc4e0021SAndy Lutomirski 	struct cpu_entry_area *cea = get_cpu_entry_area(raw_smp_processor_id());
92*dc4e0021SAndy Lutomirski 	struct doublefault_stack *ss = &cea->doublefault_stack;
93*dc4e0021SAndy Lutomirski 
94*dc4e0021SAndy Lutomirski 	void *begin = ss->stack;
95*dc4e0021SAndy Lutomirski 	void *end = begin + sizeof(ss->stack);
96*dc4e0021SAndy Lutomirski 
97*dc4e0021SAndy Lutomirski 	if ((void *)stack < begin || (void *)stack >= end)
98*dc4e0021SAndy Lutomirski 		return false;
99*dc4e0021SAndy Lutomirski 
100*dc4e0021SAndy Lutomirski 	info->type	= STACK_TYPE_EXCEPTION;
101*dc4e0021SAndy Lutomirski 	info->begin	= begin;
102*dc4e0021SAndy Lutomirski 	info->end	= end;
103*dc4e0021SAndy Lutomirski 	info->next_sp	= (unsigned long *)this_cpu_read(cpu_tss_rw.x86_tss.sp);
104*dc4e0021SAndy Lutomirski 
105*dc4e0021SAndy Lutomirski 	return true;
106*dc4e0021SAndy Lutomirski #else
107*dc4e0021SAndy Lutomirski 	return false;
108*dc4e0021SAndy Lutomirski #endif
109*dc4e0021SAndy Lutomirski }
110*dc4e0021SAndy Lutomirski 
111*dc4e0021SAndy Lutomirski 
112cb76c939SJosh Poimboeuf int get_stack_info(unsigned long *stack, struct task_struct *task,
113cb76c939SJosh Poimboeuf 		   struct stack_info *info, unsigned long *visit_mask)
114cb76c939SJosh Poimboeuf {
115cb76c939SJosh Poimboeuf 	if (!stack)
116cb76c939SJosh Poimboeuf 		goto unknown;
117cb76c939SJosh Poimboeuf 
118cb76c939SJosh Poimboeuf 	task = task ? : current;
119cb76c939SJosh Poimboeuf 
120cb76c939SJosh Poimboeuf 	if (in_task_stack(stack, task, info))
121fcd709efSJosh Poimboeuf 		goto recursion_check;
122cb76c939SJosh Poimboeuf 
123cb76c939SJosh Poimboeuf 	if (task != current)
124cb76c939SJosh Poimboeuf 		goto unknown;
125cb76c939SJosh Poimboeuf 
1264fe2d8b1SDave Hansen 	if (in_entry_stack(stack, info))
12733a2f1a6SAndy Lutomirski 		goto recursion_check;
12833a2f1a6SAndy Lutomirski 
129cb76c939SJosh Poimboeuf 	if (in_hardirq_stack(stack, info))
130fcd709efSJosh Poimboeuf 		goto recursion_check;
131cb76c939SJosh Poimboeuf 
132cb76c939SJosh Poimboeuf 	if (in_softirq_stack(stack, info))
133fcd709efSJosh Poimboeuf 		goto recursion_check;
134fcd709efSJosh Poimboeuf 
135*dc4e0021SAndy Lutomirski 	if (in_doublefault_stack(stack, info))
136*dc4e0021SAndy Lutomirski 		goto recursion_check;
137*dc4e0021SAndy Lutomirski 
138fcd709efSJosh Poimboeuf 	goto unknown;
139fcd709efSJosh Poimboeuf 
140fcd709efSJosh Poimboeuf recursion_check:
141fcd709efSJosh Poimboeuf 	/*
142fcd709efSJosh Poimboeuf 	 * Make sure we don't iterate through any given stack more than once.
143fcd709efSJosh Poimboeuf 	 * If it comes up a second time then there's something wrong going on:
144fcd709efSJosh Poimboeuf 	 * just break out and report an unknown stack type.
145fcd709efSJosh Poimboeuf 	 */
146fcd709efSJosh Poimboeuf 	if (visit_mask) {
1470d2b8579SJosh Poimboeuf 		if (*visit_mask & (1UL << info->type)) {
1480d2b8579SJosh Poimboeuf 			printk_deferred_once(KERN_WARNING "WARNING: stack recursion on stack type %d\n", info->type);
149fcd709efSJosh Poimboeuf 			goto unknown;
1500d2b8579SJosh Poimboeuf 		}
151fcd709efSJosh Poimboeuf 		*visit_mask |= 1UL << info->type;
152fcd709efSJosh Poimboeuf 	}
153fcd709efSJosh Poimboeuf 
154cb76c939SJosh Poimboeuf 	return 0;
155cb76c939SJosh Poimboeuf 
156cb76c939SJosh Poimboeuf unknown:
157cb76c939SJosh Poimboeuf 	info->type = STACK_TYPE_UNKNOWN;
158cb76c939SJosh Poimboeuf 	return -EINVAL;
159198d208dSSteven Rostedt }
160