xref: /openbmc/linux/arch/x86/kernel/dumpstack_32.c (revision 5d0e4d78)
1 /*
2  *  Copyright (C) 1991, 1992  Linus Torvalds
3  *  Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs
4  */
5 #include <linux/sched/debug.h>
6 #include <linux/kallsyms.h>
7 #include <linux/kprobes.h>
8 #include <linux/uaccess.h>
9 #include <linux/hardirq.h>
10 #include <linux/kdebug.h>
11 #include <linux/export.h>
12 #include <linux/ptrace.h>
13 #include <linux/kexec.h>
14 #include <linux/sysfs.h>
15 #include <linux/bug.h>
16 #include <linux/nmi.h>
17 
18 #include <asm/stacktrace.h>
19 
20 const char *stack_type_name(enum stack_type type)
21 {
22 	if (type == STACK_TYPE_IRQ)
23 		return "IRQ";
24 
25 	if (type == STACK_TYPE_SOFTIRQ)
26 		return "SOFTIRQ";
27 
28 	return NULL;
29 }
30 
31 static bool in_hardirq_stack(unsigned long *stack, struct stack_info *info)
32 {
33 	unsigned long *begin = (unsigned long *)this_cpu_read(hardirq_stack);
34 	unsigned long *end   = begin + (THREAD_SIZE / sizeof(long));
35 
36 	/*
37 	 * This is a software stack, so 'end' can be a valid stack pointer.
38 	 * It just means the stack is empty.
39 	 */
40 	if (stack < begin || stack > end)
41 		return false;
42 
43 	info->type	= STACK_TYPE_IRQ;
44 	info->begin	= begin;
45 	info->end	= end;
46 
47 	/*
48 	 * See irq_32.c -- the next stack pointer is stored at the beginning of
49 	 * the stack.
50 	 */
51 	info->next_sp	= (unsigned long *)*begin;
52 
53 	return true;
54 }
55 
56 static bool in_softirq_stack(unsigned long *stack, struct stack_info *info)
57 {
58 	unsigned long *begin = (unsigned long *)this_cpu_read(softirq_stack);
59 	unsigned long *end   = begin + (THREAD_SIZE / sizeof(long));
60 
61 	/*
62 	 * This is a software stack, so 'end' can be a valid stack pointer.
63 	 * It just means the stack is empty.
64 	 */
65 	if (stack < begin || stack > end)
66 		return false;
67 
68 	info->type	= STACK_TYPE_SOFTIRQ;
69 	info->begin	= begin;
70 	info->end	= end;
71 
72 	/*
73 	 * The next stack pointer is stored at the beginning of the stack.
74 	 * See irq_32.c.
75 	 */
76 	info->next_sp	= (unsigned long *)*begin;
77 
78 	return true;
79 }
80 
81 int get_stack_info(unsigned long *stack, struct task_struct *task,
82 		   struct stack_info *info, unsigned long *visit_mask)
83 {
84 	if (!stack)
85 		goto unknown;
86 
87 	task = task ? : current;
88 
89 	if (in_task_stack(stack, task, info))
90 		goto recursion_check;
91 
92 	if (task != current)
93 		goto unknown;
94 
95 	if (in_hardirq_stack(stack, info))
96 		goto recursion_check;
97 
98 	if (in_softirq_stack(stack, info))
99 		goto recursion_check;
100 
101 	goto unknown;
102 
103 recursion_check:
104 	/*
105 	 * Make sure we don't iterate through any given stack more than once.
106 	 * If it comes up a second time then there's something wrong going on:
107 	 * just break out and report an unknown stack type.
108 	 */
109 	if (visit_mask) {
110 		if (*visit_mask & (1UL << info->type)) {
111 			printk_deferred_once(KERN_WARNING "WARNING: stack recursion on stack type %d\n", info->type);
112 			goto unknown;
113 		}
114 		*visit_mask |= 1UL << info->type;
115 	}
116 
117 	return 0;
118 
119 unknown:
120 	info->type = STACK_TYPE_UNKNOWN;
121 	return -EINVAL;
122 }
123 
124 void show_regs(struct pt_regs *regs)
125 {
126 	int i;
127 
128 	show_regs_print_info(KERN_EMERG);
129 	__show_regs(regs, !user_mode(regs));
130 
131 	/*
132 	 * When in-kernel, we also print out the stack and code at the
133 	 * time of the fault..
134 	 */
135 	if (!user_mode(regs)) {
136 		unsigned int code_prologue = code_bytes * 43 / 64;
137 		unsigned int code_len = code_bytes;
138 		unsigned char c;
139 		u8 *ip;
140 
141 		show_trace_log_lvl(current, regs, NULL, KERN_EMERG);
142 
143 		pr_emerg("Code:");
144 
145 		ip = (u8 *)regs->ip - code_prologue;
146 		if (ip < (u8 *)PAGE_OFFSET || probe_kernel_address(ip, c)) {
147 			/* try starting at IP */
148 			ip = (u8 *)regs->ip;
149 			code_len = code_len - code_prologue + 1;
150 		}
151 		for (i = 0; i < code_len; i++, ip++) {
152 			if (ip < (u8 *)PAGE_OFFSET ||
153 					probe_kernel_address(ip, c)) {
154 				pr_cont("  Bad EIP value.");
155 				break;
156 			}
157 			if (ip == (u8 *)regs->ip)
158 				pr_cont(" <%02x>", c);
159 			else
160 				pr_cont(" %02x", c);
161 		}
162 	}
163 	pr_cont("\n");
164 }
165