]>
Commit | Line | Data |
---|---|---|
a17ae4c3 | 1 | // SPDX-License-Identifier: GPL-2.0 |
1bca09f7 HC |
2 | /* |
3 | * Stack dumping functions | |
4 | * | |
5 | * Copyright IBM Corp. 1999, 2013 | |
6 | */ | |
7 | ||
8 | #include <linux/kallsyms.h> | |
9 | #include <linux/hardirq.h> | |
10 | #include <linux/kprobes.h> | |
11 | #include <linux/utsname.h> | |
12 | #include <linux/export.h> | |
13 | #include <linux/kdebug.h> | |
14 | #include <linux/ptrace.h> | |
10917b83 | 15 | #include <linux/mm.h> |
1bca09f7 HC |
16 | #include <linux/module.h> |
17 | #include <linux/sched.h> | |
b17b0153 | 18 | #include <linux/sched/debug.h> |
68db0cf1 | 19 | #include <linux/sched/task_stack.h> |
1bca09f7 HC |
20 | #include <asm/processor.h> |
21 | #include <asm/debug.h> | |
0f20822a | 22 | #include <asm/dis.h> |
1bca09f7 | 23 | #include <asm/ipl.h> |
78c98f90 | 24 | #include <asm/unwind.h> |
1bca09f7 | 25 | |
78c98f90 | 26 | const char *stack_type_name(enum stack_type type) |
1bca09f7 | 27 | { |
78c98f90 MS |
28 | switch (type) { |
29 | case STACK_TYPE_TASK: | |
30 | return "task"; | |
31 | case STACK_TYPE_IRQ: | |
32 | return "irq"; | |
33 | case STACK_TYPE_NODAT: | |
34 | return "nodat"; | |
35 | case STACK_TYPE_RESTART: | |
36 | return "restart"; | |
37 | default: | |
38 | return "unknown"; | |
1bca09f7 HC |
39 | } |
40 | } | |
06101546 | 41 | EXPORT_SYMBOL_GPL(stack_type_name); |
1bca09f7 | 42 | |
78c98f90 MS |
43 | static inline bool in_stack(unsigned long sp, struct stack_info *info, |
44 | enum stack_type type, unsigned long low, | |
45 | unsigned long high) | |
46 | { | |
47 | if (sp < low || sp >= high) | |
48 | return false; | |
49 | info->type = type; | |
50 | info->begin = low; | |
51 | info->end = high; | |
52 | return true; | |
53 | } | |
54 | ||
55 | static bool in_task_stack(unsigned long sp, struct task_struct *task, | |
56 | struct stack_info *info) | |
57 | { | |
58 | unsigned long stack; | |
59 | ||
60 | stack = (unsigned long) task_stack_page(task); | |
61 | return in_stack(sp, info, STACK_TYPE_TASK, stack, stack + THREAD_SIZE); | |
62 | } | |
63 | ||
64 | static bool in_irq_stack(unsigned long sp, struct stack_info *info) | |
65 | { | |
66 | unsigned long frame_size, top; | |
67 | ||
68 | frame_size = STACK_FRAME_OVERHEAD + sizeof(struct pt_regs); | |
69 | top = S390_lowcore.async_stack + frame_size; | |
70 | return in_stack(sp, info, STACK_TYPE_IRQ, top - THREAD_SIZE, top); | |
71 | } | |
72 | ||
73 | static bool in_nodat_stack(unsigned long sp, struct stack_info *info) | |
1bca09f7 | 74 | { |
78c98f90 | 75 | unsigned long frame_size, top; |
1bca09f7 | 76 | |
758d39eb | 77 | frame_size = STACK_FRAME_OVERHEAD + sizeof(struct pt_regs); |
78c98f90 MS |
78 | top = S390_lowcore.nodat_stack + frame_size; |
79 | return in_stack(sp, info, STACK_TYPE_NODAT, top - THREAD_SIZE, top); | |
758d39eb | 80 | } |
758d39eb | 81 | |
78c98f90 | 82 | static bool in_restart_stack(unsigned long sp, struct stack_info *info) |
758d39eb | 83 | { |
78c98f90 MS |
84 | unsigned long frame_size, top; |
85 | ||
86 | frame_size = STACK_FRAME_OVERHEAD + sizeof(struct pt_regs); | |
87 | top = S390_lowcore.restart_stack + frame_size; | |
88 | return in_stack(sp, info, STACK_TYPE_RESTART, top - THREAD_SIZE, top); | |
89 | } | |
90 | ||
91 | int get_stack_info(unsigned long sp, struct task_struct *task, | |
92 | struct stack_info *info, unsigned long *visit_mask) | |
93 | { | |
94 | if (!sp) | |
95 | goto unknown; | |
96 | ||
be2d11b2 MB |
97 | /* Sanity check: ABI requires SP to be aligned 8 bytes. */ |
98 | if (sp & 0x7) | |
99 | goto unknown; | |
100 | ||
78c98f90 MS |
101 | /* Check per-task stack */ |
102 | if (in_task_stack(sp, task, info)) | |
103 | goto recursion_check; | |
104 | ||
105 | if (task != current) | |
106 | goto unknown; | |
107 | ||
108 | /* Check per-cpu stacks */ | |
109 | if (!in_irq_stack(sp, info) && | |
110 | !in_nodat_stack(sp, info) && | |
111 | !in_restart_stack(sp, info)) | |
112 | goto unknown; | |
113 | ||
114 | recursion_check: | |
115 | /* | |
116 | * Make sure we don't iterate through any given stack more than once. | |
117 | * If it comes up a second time then there's something wrong going on: | |
118 | * just break out and report an unknown stack type. | |
119 | */ | |
fd0c7435 | 120 | if (*visit_mask & (1UL << info->type)) |
78c98f90 | 121 | goto unknown; |
78c98f90 | 122 | *visit_mask |= 1UL << info->type; |
758d39eb | 123 | return 0; |
78c98f90 MS |
124 | unknown: |
125 | info->type = STACK_TYPE_UNKNOWN; | |
126 | return -EINVAL; | |
758d39eb HC |
127 | } |
128 | ||
9cb8f069 | 129 | void show_stack(struct task_struct *task, unsigned long *stack, |
8539c128 | 130 | const char *loglvl) |
758d39eb | 131 | { |
78c98f90 | 132 | struct unwind_state state; |
2b7b9817 | 133 | |
8539c128 | 134 | printk("%sCall Trace:\n", loglvl); |
78c98f90 | 135 | unwind_for_each_frame(&state, task, NULL, (unsigned long) stack) |
8539c128 DS |
136 | printk(state.reliable ? "%s [<%016lx>] %pSR \n" : |
137 | "%s([<%016lx>] %pSR)\n", | |
138 | loglvl, state.ip, (void *) state.ip); | |
78c98f90 | 139 | debug_show_held_locks(task ? : current); |
1bca09f7 HC |
140 | } |
141 | ||
1bca09f7 HC |
142 | static void show_last_breaking_event(struct pt_regs *regs) |
143 | { | |
1bca09f7 | 144 | printk("Last Breaking-Event-Address:\n"); |
8237ac3c | 145 | printk(" [<%016lx>] %pSR\n", regs->args[0], (void *)regs->args[0]); |
1bca09f7 HC |
146 | } |
147 | ||
1bca09f7 HC |
148 | void show_registers(struct pt_regs *regs) |
149 | { | |
1f021ea0 | 150 | struct psw_bits *psw = &psw_bits(regs->psw); |
1bca09f7 HC |
151 | char *mode; |
152 | ||
153 | mode = user_mode(regs) ? "User" : "Krnl"; | |
e494990e | 154 | printk("%s PSW : %px %px", mode, (void *)regs->psw.mask, (void *)regs->psw.addr); |
9ea80662 | 155 | if (!user_mode(regs)) |
a7906345 HC |
156 | pr_cont(" (%pSR)", (void *)regs->psw.addr); |
157 | pr_cont("\n"); | |
1bca09f7 | 158 | printk(" R:%x T:%x IO:%x EX:%x Key:%x M:%x W:%x " |
a7525982 HC |
159 | "P:%x AS:%x CC:%x PM:%x", psw->per, psw->dat, psw->io, psw->ext, |
160 | psw->key, psw->mcheck, psw->wait, psw->pstate, psw->as, psw->cc, psw->pm); | |
a7906345 HC |
161 | pr_cont(" RI:%x EA:%x\n", psw->ri, psw->eaba); |
162 | printk("%s GPRS: %016lx %016lx %016lx %016lx\n", mode, | |
1bca09f7 | 163 | regs->gprs[0], regs->gprs[1], regs->gprs[2], regs->gprs[3]); |
5a79859a | 164 | printk(" %016lx %016lx %016lx %016lx\n", |
1bca09f7 | 165 | regs->gprs[4], regs->gprs[5], regs->gprs[6], regs->gprs[7]); |
5a79859a | 166 | printk(" %016lx %016lx %016lx %016lx\n", |
1bca09f7 | 167 | regs->gprs[8], regs->gprs[9], regs->gprs[10], regs->gprs[11]); |
5a79859a | 168 | printk(" %016lx %016lx %016lx %016lx\n", |
1bca09f7 HC |
169 | regs->gprs[12], regs->gprs[13], regs->gprs[14], regs->gprs[15]); |
170 | show_code(regs); | |
171 | } | |
172 | ||
173 | void show_regs(struct pt_regs *regs) | |
174 | { | |
a43cb95d | 175 | show_regs_print_info(KERN_DEFAULT); |
1bca09f7 HC |
176 | show_registers(regs); |
177 | /* Show stack backtrace if pt_regs is from kernel mode */ | |
178 | if (!user_mode(regs)) | |
9cb8f069 | 179 | show_stack(NULL, (unsigned long *) regs->gprs[15], KERN_DEFAULT); |
1bca09f7 HC |
180 | show_last_breaking_event(regs); |
181 | } | |
182 | ||
183 | static DEFINE_SPINLOCK(die_lock); | |
184 | ||
185 | void die(struct pt_regs *regs, const char *str) | |
186 | { | |
187 | static int die_counter; | |
188 | ||
189 | oops_enter(); | |
190 | lgr_info_log(); | |
191 | debug_stop_all(); | |
192 | console_verbose(); | |
193 | spin_lock_irq(&die_lock); | |
194 | bust_spinlocks(1); | |
413d4047 HC |
195 | printk("%s: %04x ilc:%d [#%d] ", str, regs->int_code & 0xffff, |
196 | regs->int_code >> 17, ++die_counter); | |
1bca09f7 | 197 | #ifdef CONFIG_PREEMPT |
47ece7fe | 198 | pr_cont("PREEMPT "); |
fa686453 TG |
199 | #elif defined(CONFIG_PREEMPT_RT) |
200 | pr_cont("PREEMPT_RT "); | |
1bca09f7 | 201 | #endif |
47ece7fe | 202 | pr_cont("SMP "); |
10917b83 | 203 | if (debug_pagealloc_enabled()) |
47ece7fe HC |
204 | pr_cont("DEBUG_PAGEALLOC"); |
205 | pr_cont("\n"); | |
1bca09f7 HC |
206 | notify_die(DIE_OOPS, str, regs, 0, regs->int_code & 0xffff, SIGSEGV); |
207 | print_modules(); | |
208 | show_regs(regs); | |
209 | bust_spinlocks(0); | |
210 | add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE); | |
211 | spin_unlock_irq(&die_lock); | |
212 | if (in_interrupt()) | |
213 | panic("Fatal exception in interrupt"); | |
214 | if (panic_on_oops) | |
215 | panic("Fatal exception: panic_on_oops"); | |
216 | oops_exit(); | |
217 | do_exit(SIGSEGV); | |
218 | } |