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