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