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