xref: /linux/arch/x86/kernel/dumpstack_32.c (revision 7ae9fb1b7ecbb5d85d07857943f677fd1a559b18)
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 
stack_type_name(enum stack_type type)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 
32dc4e0021SAndy Lutomirski 	if (type == STACK_TYPE_EXCEPTION)
33dc4e0021SAndy Lutomirski 		return "#DF";
34dc4e0021SAndy Lutomirski 
353d02a9c4SJosh Poimboeuf 	return NULL;
36198d208dSSteven Rostedt }
37198d208dSSteven Rostedt 
in_hardirq_stack(unsigned long * stack,struct stack_info * info)38cb76c939SJosh Poimboeuf static bool in_hardirq_stack(unsigned long *stack, struct stack_info *info)
39198d208dSSteven Rostedt {
40*d7b6d709SThomas Gleixner 	unsigned long *begin = (unsigned long *)this_cpu_read(pcpu_hot.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 
in_softirq_stack(unsigned long * stack,struct stack_info * info)63cb76c939SJosh Poimboeuf static bool in_softirq_stack(unsigned long *stack, struct stack_info *info)
64198d208dSSteven Rostedt {
65*d7b6d709SThomas Gleixner 	unsigned long *begin = (unsigned long *)this_cpu_read(pcpu_hot.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 
in_doublefault_stack(unsigned long * stack,struct stack_info * info)88dc4e0021SAndy Lutomirski static bool in_doublefault_stack(unsigned long *stack, struct stack_info *info)
89dc4e0021SAndy Lutomirski {
90dc4e0021SAndy Lutomirski 	struct cpu_entry_area *cea = get_cpu_entry_area(raw_smp_processor_id());
91dc4e0021SAndy Lutomirski 	struct doublefault_stack *ss = &cea->doublefault_stack;
92dc4e0021SAndy Lutomirski 
93dc4e0021SAndy Lutomirski 	void *begin = ss->stack;
94dc4e0021SAndy Lutomirski 	void *end = begin + sizeof(ss->stack);
95dc4e0021SAndy Lutomirski 
96dc4e0021SAndy Lutomirski 	if ((void *)stack < begin || (void *)stack >= end)
97dc4e0021SAndy Lutomirski 		return false;
98dc4e0021SAndy Lutomirski 
99dc4e0021SAndy Lutomirski 	info->type	= STACK_TYPE_EXCEPTION;
100dc4e0021SAndy Lutomirski 	info->begin	= begin;
101dc4e0021SAndy Lutomirski 	info->end	= end;
102dc4e0021SAndy Lutomirski 	info->next_sp	= (unsigned long *)this_cpu_read(cpu_tss_rw.x86_tss.sp);
103dc4e0021SAndy Lutomirski 
104dc4e0021SAndy Lutomirski 	return true;
105dc4e0021SAndy Lutomirski }
106dc4e0021SAndy Lutomirski 
107dc4e0021SAndy Lutomirski 
get_stack_info(unsigned long * stack,struct task_struct * task,struct stack_info * info,unsigned long * visit_mask)108cb76c939SJosh Poimboeuf int get_stack_info(unsigned long *stack, struct task_struct *task,
109cb76c939SJosh Poimboeuf 		   struct stack_info *info, unsigned long *visit_mask)
110cb76c939SJosh Poimboeuf {
111cb76c939SJosh Poimboeuf 	if (!stack)
112cb76c939SJosh Poimboeuf 		goto unknown;
113cb76c939SJosh Poimboeuf 
114cb76c939SJosh Poimboeuf 	task = task ? : current;
115cb76c939SJosh Poimboeuf 
116cb76c939SJosh Poimboeuf 	if (in_task_stack(stack, task, info))
117fcd709efSJosh Poimboeuf 		goto recursion_check;
118cb76c939SJosh Poimboeuf 
119cb76c939SJosh Poimboeuf 	if (task != current)
120cb76c939SJosh Poimboeuf 		goto unknown;
121cb76c939SJosh Poimboeuf 
1224fe2d8b1SDave Hansen 	if (in_entry_stack(stack, info))
12333a2f1a6SAndy Lutomirski 		goto recursion_check;
12433a2f1a6SAndy Lutomirski 
125cb76c939SJosh Poimboeuf 	if (in_hardirq_stack(stack, info))
126fcd709efSJosh Poimboeuf 		goto recursion_check;
127cb76c939SJosh Poimboeuf 
128cb76c939SJosh Poimboeuf 	if (in_softirq_stack(stack, info))
129fcd709efSJosh Poimboeuf 		goto recursion_check;
130fcd709efSJosh Poimboeuf 
131dc4e0021SAndy Lutomirski 	if (in_doublefault_stack(stack, info))
132dc4e0021SAndy Lutomirski 		goto recursion_check;
133dc4e0021SAndy Lutomirski 
134fcd709efSJosh Poimboeuf 	goto unknown;
135fcd709efSJosh Poimboeuf 
136fcd709efSJosh Poimboeuf recursion_check:
137fcd709efSJosh Poimboeuf 	/*
138fcd709efSJosh Poimboeuf 	 * Make sure we don't iterate through any given stack more than once.
139fcd709efSJosh Poimboeuf 	 * If it comes up a second time then there's something wrong going on:
140fcd709efSJosh Poimboeuf 	 * just break out and report an unknown stack type.
141fcd709efSJosh Poimboeuf 	 */
142fcd709efSJosh Poimboeuf 	if (visit_mask) {
1430d2b8579SJosh Poimboeuf 		if (*visit_mask & (1UL << info->type)) {
1440d2b8579SJosh Poimboeuf 			printk_deferred_once(KERN_WARNING "WARNING: stack recursion on stack type %d\n", info->type);
145fcd709efSJosh Poimboeuf 			goto unknown;
1460d2b8579SJosh Poimboeuf 		}
147fcd709efSJosh Poimboeuf 		*visit_mask |= 1UL << info->type;
148fcd709efSJosh Poimboeuf 	}
149fcd709efSJosh Poimboeuf 
150cb76c939SJosh Poimboeuf 	return 0;
151cb76c939SJosh Poimboeuf 
152cb76c939SJosh Poimboeuf unknown:
153cb76c939SJosh Poimboeuf 	info->type = STACK_TYPE_UNKNOWN;
154cb76c939SJosh Poimboeuf 	return -EINVAL;
155198d208dSSteven Rostedt }
156