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