]>
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 HC |
23 | #include <asm/ipl.h> |
24 | ||
1bca09f7 | 25 | /* |
758d39eb | 26 | * For dump_trace we have tree different stack to consider: |
1bca09f7 HC |
27 | * - the panic stack which is used if the kernel stack has overflown |
28 | * - the asynchronous interrupt stack (cpu related) | |
29 | * - the synchronous kernel stack (process related) | |
758d39eb | 30 | * The stack trace can start at any of the three stacks and can potentially |
1bca09f7 HC |
31 | * touch all of them. The order is: panic stack, async stack, sync stack. |
32 | */ | |
33 | static unsigned long | |
758d39eb HC |
34 | __dump_trace(dump_trace_func_t func, void *data, unsigned long sp, |
35 | unsigned long low, unsigned long high) | |
1bca09f7 HC |
36 | { |
37 | struct stack_frame *sf; | |
38 | struct pt_regs *regs; | |
39 | ||
40 | while (1) { | |
1bca09f7 HC |
41 | if (sp < low || sp > high - sizeof(*sf)) |
42 | return sp; | |
43 | sf = (struct stack_frame *) sp; | |
d0208639 HC |
44 | if (func(data, sf->gprs[8], 0)) |
45 | return sp; | |
1bca09f7 HC |
46 | /* Follow the backchain. */ |
47 | while (1) { | |
48 | low = sp; | |
9cb1ccec | 49 | sp = sf->back_chain; |
1bca09f7 HC |
50 | if (!sp) |
51 | break; | |
52 | if (sp <= low || sp > high - sizeof(*sf)) | |
53 | return sp; | |
54 | sf = (struct stack_frame *) sp; | |
d0208639 HC |
55 | if (func(data, sf->gprs[8], 1)) |
56 | return sp; | |
1bca09f7 HC |
57 | } |
58 | /* Zero backchain detected, check for interrupt frame. */ | |
59 | sp = (unsigned long) (sf + 1); | |
60 | if (sp <= low || sp > high - sizeof(*regs)) | |
61 | return sp; | |
62 | regs = (struct pt_regs *) sp; | |
758d39eb | 63 | if (!user_mode(regs)) { |
d0208639 | 64 | if (func(data, regs->psw.addr, 1)) |
758d39eb HC |
65 | return sp; |
66 | } | |
1bca09f7 HC |
67 | low = sp; |
68 | sp = regs->gprs[15]; | |
69 | } | |
70 | } | |
71 | ||
758d39eb HC |
72 | void dump_trace(dump_trace_func_t func, void *data, struct task_struct *task, |
73 | unsigned long sp) | |
1bca09f7 | 74 | { |
758d39eb | 75 | unsigned long frame_size; |
1bca09f7 | 76 | |
758d39eb | 77 | frame_size = STACK_FRAME_OVERHEAD + sizeof(struct pt_regs); |
1bca09f7 | 78 | #ifdef CONFIG_CHECK_STACK |
758d39eb | 79 | sp = __dump_trace(func, data, sp, |
f1c1174f | 80 | S390_lowcore.panic_stack + frame_size - PAGE_SIZE, |
9cc5c206 | 81 | S390_lowcore.panic_stack + frame_size); |
1bca09f7 | 82 | #endif |
758d39eb | 83 | sp = __dump_trace(func, data, sp, |
9cc5c206 MS |
84 | S390_lowcore.async_stack + frame_size - ASYNC_SIZE, |
85 | S390_lowcore.async_stack + frame_size); | |
c3bdf2e1 HC |
86 | task = task ?: current; |
87 | __dump_trace(func, data, sp, | |
88 | (unsigned long)task_stack_page(task), | |
89 | (unsigned long)task_stack_page(task) + THREAD_SIZE); | |
758d39eb HC |
90 | } |
91 | EXPORT_SYMBOL_GPL(dump_trace); | |
92 | ||
d0208639 | 93 | static int show_address(void *data, unsigned long address, int reliable) |
758d39eb | 94 | { |
d0208639 HC |
95 | if (reliable) |
96 | printk(" [<%016lx>] %pSR \n", address, (void *)address); | |
97 | else | |
98 | printk("([<%016lx>] %pSR)\n", address, (void *)address); | |
758d39eb HC |
99 | return 0; |
100 | } | |
101 | ||
2b7b9817 | 102 | void show_stack(struct task_struct *task, unsigned long *stack) |
758d39eb | 103 | { |
2b7b9817 HC |
104 | unsigned long sp = (unsigned long) stack; |
105 | ||
758d39eb HC |
106 | if (!sp) |
107 | sp = task ? task->thread.ksp : current_stack_pointer(); | |
108 | printk("Call Trace:\n"); | |
109 | dump_trace(show_address, NULL, task, sp); | |
1bca09f7 HC |
110 | if (!task) |
111 | task = current; | |
112 | debug_show_held_locks(task); | |
113 | } | |
114 | ||
1bca09f7 HC |
115 | static void show_last_breaking_event(struct pt_regs *regs) |
116 | { | |
1bca09f7 | 117 | printk("Last Breaking-Event-Address:\n"); |
8237ac3c | 118 | printk(" [<%016lx>] %pSR\n", regs->args[0], (void *)regs->args[0]); |
1bca09f7 HC |
119 | } |
120 | ||
1bca09f7 HC |
121 | void show_registers(struct pt_regs *regs) |
122 | { | |
1f021ea0 | 123 | struct psw_bits *psw = &psw_bits(regs->psw); |
1bca09f7 HC |
124 | char *mode; |
125 | ||
126 | mode = user_mode(regs) ? "User" : "Krnl"; | |
9ea80662 HC |
127 | printk("%s PSW : %p %p", mode, (void *)regs->psw.mask, (void *)regs->psw.addr); |
128 | if (!user_mode(regs)) | |
a7906345 HC |
129 | pr_cont(" (%pSR)", (void *)regs->psw.addr); |
130 | pr_cont("\n"); | |
1bca09f7 | 131 | printk(" R:%x T:%x IO:%x EX:%x Key:%x M:%x W:%x " |
a7525982 HC |
132 | "P:%x AS:%x CC:%x PM:%x", psw->per, psw->dat, psw->io, psw->ext, |
133 | psw->key, psw->mcheck, psw->wait, psw->pstate, psw->as, psw->cc, psw->pm); | |
a7906345 HC |
134 | pr_cont(" RI:%x EA:%x\n", psw->ri, psw->eaba); |
135 | printk("%s GPRS: %016lx %016lx %016lx %016lx\n", mode, | |
1bca09f7 | 136 | regs->gprs[0], regs->gprs[1], regs->gprs[2], regs->gprs[3]); |
5a79859a | 137 | printk(" %016lx %016lx %016lx %016lx\n", |
1bca09f7 | 138 | regs->gprs[4], regs->gprs[5], regs->gprs[6], regs->gprs[7]); |
5a79859a | 139 | printk(" %016lx %016lx %016lx %016lx\n", |
1bca09f7 | 140 | regs->gprs[8], regs->gprs[9], regs->gprs[10], regs->gprs[11]); |
5a79859a | 141 | printk(" %016lx %016lx %016lx %016lx\n", |
1bca09f7 HC |
142 | regs->gprs[12], regs->gprs[13], regs->gprs[14], regs->gprs[15]); |
143 | show_code(regs); | |
144 | } | |
145 | ||
146 | void show_regs(struct pt_regs *regs) | |
147 | { | |
a43cb95d | 148 | show_regs_print_info(KERN_DEFAULT); |
1bca09f7 HC |
149 | show_registers(regs); |
150 | /* Show stack backtrace if pt_regs is from kernel mode */ | |
151 | if (!user_mode(regs)) | |
2b7b9817 | 152 | show_stack(NULL, (unsigned long *) regs->gprs[15]); |
1bca09f7 HC |
153 | show_last_breaking_event(regs); |
154 | } | |
155 | ||
156 | static DEFINE_SPINLOCK(die_lock); | |
157 | ||
158 | void die(struct pt_regs *regs, const char *str) | |
159 | { | |
160 | static int die_counter; | |
161 | ||
162 | oops_enter(); | |
163 | lgr_info_log(); | |
164 | debug_stop_all(); | |
165 | console_verbose(); | |
166 | spin_lock_irq(&die_lock); | |
167 | bust_spinlocks(1); | |
413d4047 HC |
168 | printk("%s: %04x ilc:%d [#%d] ", str, regs->int_code & 0xffff, |
169 | regs->int_code >> 17, ++die_counter); | |
1bca09f7 | 170 | #ifdef CONFIG_PREEMPT |
47ece7fe | 171 | pr_cont("PREEMPT "); |
1bca09f7 HC |
172 | #endif |
173 | #ifdef CONFIG_SMP | |
47ece7fe | 174 | pr_cont("SMP "); |
1bca09f7 | 175 | #endif |
10917b83 | 176 | if (debug_pagealloc_enabled()) |
47ece7fe HC |
177 | pr_cont("DEBUG_PAGEALLOC"); |
178 | pr_cont("\n"); | |
1bca09f7 HC |
179 | notify_die(DIE_OOPS, str, regs, 0, regs->int_code & 0xffff, SIGSEGV); |
180 | print_modules(); | |
181 | show_regs(regs); | |
182 | bust_spinlocks(0); | |
183 | add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE); | |
184 | spin_unlock_irq(&die_lock); | |
185 | if (in_interrupt()) | |
186 | panic("Fatal exception in interrupt"); | |
187 | if (panic_on_oops) | |
188 | panic("Fatal exception: panic_on_oops"); | |
189 | oops_exit(); | |
190 | do_exit(SIGSEGV); | |
191 | } |