]>
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, |
f1c1174f | 79 | S390_lowcore.panic_stack + frame_size - PAGE_SIZE, |
9cc5c206 | 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 | ||
2b7b9817 | 101 | void show_stack(struct task_struct *task, unsigned long *stack) |
758d39eb | 102 | { |
2b7b9817 HC |
103 | unsigned long sp = (unsigned long) stack; |
104 | ||
758d39eb HC |
105 | if (!sp) |
106 | sp = task ? task->thread.ksp : current_stack_pointer(); | |
107 | printk("Call Trace:\n"); | |
108 | dump_trace(show_address, NULL, task, sp); | |
1bca09f7 HC |
109 | if (!task) |
110 | task = current; | |
111 | debug_show_held_locks(task); | |
112 | } | |
113 | ||
1bca09f7 HC |
114 | static void show_last_breaking_event(struct pt_regs *regs) |
115 | { | |
1bca09f7 | 116 | printk("Last Breaking-Event-Address:\n"); |
8237ac3c | 117 | printk(" [<%016lx>] %pSR\n", regs->args[0], (void *)regs->args[0]); |
1bca09f7 HC |
118 | } |
119 | ||
1bca09f7 HC |
120 | void show_registers(struct pt_regs *regs) |
121 | { | |
1f021ea0 | 122 | struct psw_bits *psw = &psw_bits(regs->psw); |
1bca09f7 HC |
123 | char *mode; |
124 | ||
125 | mode = user_mode(regs) ? "User" : "Krnl"; | |
9ea80662 HC |
126 | printk("%s PSW : %p %p", mode, (void *)regs->psw.mask, (void *)regs->psw.addr); |
127 | if (!user_mode(regs)) | |
a7906345 HC |
128 | pr_cont(" (%pSR)", (void *)regs->psw.addr); |
129 | pr_cont("\n"); | |
1bca09f7 | 130 | printk(" R:%x T:%x IO:%x EX:%x Key:%x M:%x W:%x " |
a7525982 HC |
131 | "P:%x AS:%x CC:%x PM:%x", psw->per, psw->dat, psw->io, psw->ext, |
132 | psw->key, psw->mcheck, psw->wait, psw->pstate, psw->as, psw->cc, psw->pm); | |
a7906345 HC |
133 | pr_cont(" RI:%x EA:%x\n", psw->ri, psw->eaba); |
134 | printk("%s GPRS: %016lx %016lx %016lx %016lx\n", mode, | |
1bca09f7 | 135 | regs->gprs[0], regs->gprs[1], regs->gprs[2], regs->gprs[3]); |
5a79859a | 136 | printk(" %016lx %016lx %016lx %016lx\n", |
1bca09f7 | 137 | regs->gprs[4], regs->gprs[5], regs->gprs[6], regs->gprs[7]); |
5a79859a | 138 | printk(" %016lx %016lx %016lx %016lx\n", |
1bca09f7 | 139 | regs->gprs[8], regs->gprs[9], regs->gprs[10], regs->gprs[11]); |
5a79859a | 140 | printk(" %016lx %016lx %016lx %016lx\n", |
1bca09f7 HC |
141 | regs->gprs[12], regs->gprs[13], regs->gprs[14], regs->gprs[15]); |
142 | show_code(regs); | |
143 | } | |
144 | ||
145 | void show_regs(struct pt_regs *regs) | |
146 | { | |
a43cb95d | 147 | show_regs_print_info(KERN_DEFAULT); |
1bca09f7 HC |
148 | show_registers(regs); |
149 | /* Show stack backtrace if pt_regs is from kernel mode */ | |
150 | if (!user_mode(regs)) | |
2b7b9817 | 151 | show_stack(NULL, (unsigned long *) regs->gprs[15]); |
1bca09f7 HC |
152 | show_last_breaking_event(regs); |
153 | } | |
154 | ||
155 | static DEFINE_SPINLOCK(die_lock); | |
156 | ||
157 | void die(struct pt_regs *regs, const char *str) | |
158 | { | |
159 | static int die_counter; | |
160 | ||
161 | oops_enter(); | |
162 | lgr_info_log(); | |
163 | debug_stop_all(); | |
164 | console_verbose(); | |
165 | spin_lock_irq(&die_lock); | |
166 | bust_spinlocks(1); | |
413d4047 HC |
167 | printk("%s: %04x ilc:%d [#%d] ", str, regs->int_code & 0xffff, |
168 | regs->int_code >> 17, ++die_counter); | |
1bca09f7 | 169 | #ifdef CONFIG_PREEMPT |
47ece7fe | 170 | pr_cont("PREEMPT "); |
1bca09f7 HC |
171 | #endif |
172 | #ifdef CONFIG_SMP | |
47ece7fe | 173 | pr_cont("SMP "); |
1bca09f7 | 174 | #endif |
10917b83 | 175 | if (debug_pagealloc_enabled()) |
47ece7fe HC |
176 | pr_cont("DEBUG_PAGEALLOC"); |
177 | pr_cont("\n"); | |
1bca09f7 HC |
178 | notify_die(DIE_OOPS, str, regs, 0, regs->int_code & 0xffff, SIGSEGV); |
179 | print_modules(); | |
180 | show_regs(regs); | |
181 | bust_spinlocks(0); | |
182 | add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE); | |
183 | spin_unlock_irq(&die_lock); | |
184 | if (in_interrupt()) | |
185 | panic("Fatal exception in interrupt"); | |
186 | if (panic_on_oops) | |
187 | panic("Fatal exception: panic_on_oops"); | |
188 | oops_exit(); | |
189 | do_exit(SIGSEGV); | |
190 | } |