diff options
Diffstat (limited to 'arch/s390')
| -rw-r--r-- | arch/s390/kernel/Makefile | 17 | ||||
| -rw-r--r-- | arch/s390/kernel/dumpstack.c | 236 | ||||
| -rw-r--r-- | arch/s390/kernel/traps.c | 250 |
3 files changed, 253 insertions, 250 deletions
diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile index 2ac311ef5c9b..1386fcaf4ef6 100644 --- a/arch/s390/kernel/Makefile +++ b/arch/s390/kernel/Makefile | |||
| @@ -14,16 +14,25 @@ endif | |||
| 14 | CFLAGS_smp.o := -Wno-nonnull | 14 | CFLAGS_smp.o := -Wno-nonnull |
| 15 | 15 | ||
| 16 | # | 16 | # |
| 17 | # Disable tailcall optimizations for stack / callchain walking functions | ||
| 18 | # since this might generate broken code when accessing register 15 and | ||
| 19 | # passing its content to other functions. | ||
| 20 | # | ||
| 21 | CFLAGS_stacktrace.o += -fno-optimize-sibling-calls | ||
| 22 | CFLAGS_dumpstack.o += -fno-optimize-sibling-calls | ||
| 23 | |||
| 24 | # | ||
| 17 | # Pass UTS_MACHINE for user_regset definition | 25 | # Pass UTS_MACHINE for user_regset definition |
| 18 | # | 26 | # |
| 19 | CFLAGS_ptrace.o += -DUTS_MACHINE='"$(UTS_MACHINE)"' | 27 | CFLAGS_ptrace.o += -DUTS_MACHINE='"$(UTS_MACHINE)"' |
| 20 | 28 | ||
| 21 | CFLAGS_sysinfo.o += -Iinclude/math-emu -Iarch/s390/math-emu -w | 29 | CFLAGS_sysinfo.o += -Iinclude/math-emu -Iarch/s390/math-emu -w |
| 22 | 30 | ||
| 23 | obj-y := bitmap.o traps.o time.o process.o base.o early.o setup.o vtime.o \ | 31 | obj-y := bitmap.o traps.o time.o process.o base.o early.o setup.o vtime.o |
| 24 | processor.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o nmi.o \ | 32 | obj-y += processor.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o nmi.o |
| 25 | debug.o irq.o ipl.o dis.o diag.o mem_detect.o sclp.o vdso.o \ | 33 | obj-y += debug.o irq.o ipl.o dis.o diag.o mem_detect.o sclp.o vdso.o |
| 26 | sysinfo.o jump_label.o lgr.o os_info.o machine_kexec.o pgm_check.o | 34 | obj-y += sysinfo.o jump_label.o lgr.o os_info.o machine_kexec.o pgm_check.o |
| 35 | obj-y += dumpstack.o | ||
| 27 | 36 | ||
| 28 | obj-y += $(if $(CONFIG_64BIT),entry64.o,entry.o) | 37 | obj-y += $(if $(CONFIG_64BIT),entry64.o,entry.o) |
| 29 | obj-y += $(if $(CONFIG_64BIT),reipl64.o,reipl.o) | 38 | obj-y += $(if $(CONFIG_64BIT),reipl64.o,reipl.o) |
diff --git a/arch/s390/kernel/dumpstack.c b/arch/s390/kernel/dumpstack.c new file mode 100644 index 000000000000..03dce39d01ee --- /dev/null +++ b/arch/s390/kernel/dumpstack.c | |||
| @@ -0,0 +1,236 @@ | |||
| 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> | ||
| 14 | #include <linux/module.h> | ||
| 15 | #include <linux/sched.h> | ||
| 16 | #include <asm/processor.h> | ||
| 17 | #include <asm/debug.h> | ||
| 18 | #include <asm/ipl.h> | ||
| 19 | |||
| 20 | #ifndef CONFIG_64BIT | ||
| 21 | #define LONG "%08lx " | ||
| 22 | #define FOURLONG "%08lx %08lx %08lx %08lx\n" | ||
| 23 | static int kstack_depth_to_print = 12; | ||
| 24 | #else /* CONFIG_64BIT */ | ||
| 25 | #define LONG "%016lx " | ||
| 26 | #define FOURLONG "%016lx %016lx %016lx %016lx\n" | ||
| 27 | static int kstack_depth_to_print = 20; | ||
| 28 | #endif /* CONFIG_64BIT */ | ||
| 29 | |||
| 30 | /* | ||
| 31 | * For show_trace we have tree different stack to consider: | ||
| 32 | * - the panic stack which is used if the kernel stack has overflown | ||
| 33 | * - the asynchronous interrupt stack (cpu related) | ||
| 34 | * - the synchronous kernel stack (process related) | ||
| 35 | * The stack trace can start at any of the three stack and can potentially | ||
| 36 | * touch all of them. The order is: panic stack, async stack, sync stack. | ||
| 37 | */ | ||
| 38 | static unsigned long | ||
| 39 | __show_trace(unsigned long sp, unsigned long low, unsigned long high) | ||
| 40 | { | ||
| 41 | struct stack_frame *sf; | ||
| 42 | struct pt_regs *regs; | ||
| 43 | |||
| 44 | while (1) { | ||
| 45 | sp = sp & PSW_ADDR_INSN; | ||
| 46 | if (sp < low || sp > high - sizeof(*sf)) | ||
| 47 | return sp; | ||
| 48 | sf = (struct stack_frame *) sp; | ||
| 49 | printk("([<%016lx>] ", sf->gprs[8] & PSW_ADDR_INSN); | ||
| 50 | print_symbol("%s)\n", sf->gprs[8] & PSW_ADDR_INSN); | ||
| 51 | /* Follow the backchain. */ | ||
| 52 | while (1) { | ||
| 53 | low = sp; | ||
| 54 | sp = sf->back_chain & PSW_ADDR_INSN; | ||
| 55 | if (!sp) | ||
| 56 | break; | ||
| 57 | if (sp <= low || sp > high - sizeof(*sf)) | ||
| 58 | return sp; | ||
| 59 | sf = (struct stack_frame *) sp; | ||
| 60 | printk(" [<%016lx>] ", sf->gprs[8] & PSW_ADDR_INSN); | ||
| 61 | print_symbol("%s\n", sf->gprs[8] & PSW_ADDR_INSN); | ||
| 62 | } | ||
| 63 | /* Zero backchain detected, check for interrupt frame. */ | ||
| 64 | sp = (unsigned long) (sf + 1); | ||
| 65 | if (sp <= low || sp > high - sizeof(*regs)) | ||
| 66 | return sp; | ||
| 67 | regs = (struct pt_regs *) sp; | ||
| 68 | printk(" [<%016lx>] ", regs->psw.addr & PSW_ADDR_INSN); | ||
| 69 | print_symbol("%s\n", regs->psw.addr & PSW_ADDR_INSN); | ||
| 70 | low = sp; | ||
| 71 | sp = regs->gprs[15]; | ||
| 72 | } | ||
| 73 | } | ||
| 74 | |||
| 75 | static void show_trace(struct task_struct *task, unsigned long *stack) | ||
| 76 | { | ||
| 77 | register unsigned long __r15 asm ("15"); | ||
| 78 | unsigned long sp; | ||
| 79 | |||
| 80 | sp = (unsigned long) stack; | ||
| 81 | if (!sp) | ||
| 82 | sp = task ? task->thread.ksp : __r15; | ||
| 83 | printk("Call Trace:\n"); | ||
| 84 | #ifdef CONFIG_CHECK_STACK | ||
| 85 | sp = __show_trace(sp, S390_lowcore.panic_stack - 4096, | ||
| 86 | S390_lowcore.panic_stack); | ||
| 87 | #endif | ||
| 88 | sp = __show_trace(sp, S390_lowcore.async_stack - ASYNC_SIZE, | ||
| 89 | S390_lowcore.async_stack); | ||
| 90 | if (task) | ||
| 91 | __show_trace(sp, (unsigned long) task_stack_page(task), | ||
| 92 | (unsigned long) task_stack_page(task) + THREAD_SIZE); | ||
| 93 | else | ||
| 94 | __show_trace(sp, S390_lowcore.thread_info, | ||
| 95 | S390_lowcore.thread_info + THREAD_SIZE); | ||
| 96 | if (!task) | ||
| 97 | task = current; | ||
| 98 | debug_show_held_locks(task); | ||
| 99 | } | ||
| 100 | |||
| 101 | void show_stack(struct task_struct *task, unsigned long *sp) | ||
| 102 | { | ||
| 103 | register unsigned long *__r15 asm ("15"); | ||
| 104 | unsigned long *stack; | ||
| 105 | int i; | ||
| 106 | |||
| 107 | if (!sp) | ||
| 108 | stack = task ? (unsigned long *) task->thread.ksp : __r15; | ||
| 109 | else | ||
| 110 | stack = sp; | ||
| 111 | |||
| 112 | for (i = 0; i < kstack_depth_to_print; i++) { | ||
| 113 | if (((addr_t) stack & (THREAD_SIZE-1)) == 0) | ||
| 114 | break; | ||
| 115 | if ((i * sizeof(long) % 32) == 0) | ||
| 116 | printk("%s ", i == 0 ? "" : "\n"); | ||
| 117 | printk(LONG, *stack++); | ||
| 118 | } | ||
| 119 | printk("\n"); | ||
| 120 | show_trace(task, sp); | ||
| 121 | } | ||
| 122 | |||
| 123 | static void show_last_breaking_event(struct pt_regs *regs) | ||
| 124 | { | ||
| 125 | #ifdef CONFIG_64BIT | ||
| 126 | printk("Last Breaking-Event-Address:\n"); | ||
| 127 | printk(" [<%016lx>] ", regs->args[0] & PSW_ADDR_INSN); | ||
| 128 | print_symbol("%s\n", regs->args[0] & PSW_ADDR_INSN); | ||
| 129 | #endif | ||
| 130 | } | ||
| 131 | |||
| 132 | /* | ||
| 133 | * The architecture-independent dump_stack generator | ||
| 134 | */ | ||
| 135 | void dump_stack(void) | ||
| 136 | { | ||
| 137 | printk("CPU: %d %s %s %.*s\n", | ||
| 138 | task_thread_info(current)->cpu, print_tainted(), | ||
| 139 | init_utsname()->release, | ||
| 140 | (int)strcspn(init_utsname()->version, " "), | ||
| 141 | init_utsname()->version); | ||
| 142 | printk("Process %s (pid: %d, task: %p, ksp: %p)\n", | ||
| 143 | current->comm, current->pid, current, | ||
| 144 | (void *) current->thread.ksp); | ||
| 145 | show_stack(NULL, NULL); | ||
| 146 | } | ||
| 147 | EXPORT_SYMBOL(dump_stack); | ||
| 148 | |||
| 149 | static inline int mask_bits(struct pt_regs *regs, unsigned long bits) | ||
| 150 | { | ||
| 151 | return (regs->psw.mask & bits) / ((~bits + 1) & bits); | ||
| 152 | } | ||
| 153 | |||
| 154 | void show_registers(struct pt_regs *regs) | ||
| 155 | { | ||
| 156 | char *mode; | ||
| 157 | |||
| 158 | mode = user_mode(regs) ? "User" : "Krnl"; | ||
| 159 | printk("%s PSW : %p %p", | ||
| 160 | mode, (void *) regs->psw.mask, | ||
| 161 | (void *) regs->psw.addr); | ||
| 162 | print_symbol(" (%s)\n", regs->psw.addr & PSW_ADDR_INSN); | ||
| 163 | printk(" R:%x T:%x IO:%x EX:%x Key:%x M:%x W:%x " | ||
| 164 | "P:%x AS:%x CC:%x PM:%x", mask_bits(regs, PSW_MASK_PER), | ||
| 165 | mask_bits(regs, PSW_MASK_DAT), mask_bits(regs, PSW_MASK_IO), | ||
| 166 | mask_bits(regs, PSW_MASK_EXT), mask_bits(regs, PSW_MASK_KEY), | ||
| 167 | mask_bits(regs, PSW_MASK_MCHECK), mask_bits(regs, PSW_MASK_WAIT), | ||
| 168 | mask_bits(regs, PSW_MASK_PSTATE), mask_bits(regs, PSW_MASK_ASC), | ||
| 169 | mask_bits(regs, PSW_MASK_CC), mask_bits(regs, PSW_MASK_PM)); | ||
| 170 | #ifdef CONFIG_64BIT | ||
| 171 | printk(" EA:%x", mask_bits(regs, PSW_MASK_EA | PSW_MASK_BA)); | ||
| 172 | #endif | ||
| 173 | printk("\n%s GPRS: " FOURLONG, mode, | ||
| 174 | regs->gprs[0], regs->gprs[1], regs->gprs[2], regs->gprs[3]); | ||
| 175 | printk(" " FOURLONG, | ||
| 176 | regs->gprs[4], regs->gprs[5], regs->gprs[6], regs->gprs[7]); | ||
| 177 | printk(" " FOURLONG, | ||
| 178 | regs->gprs[8], regs->gprs[9], regs->gprs[10], regs->gprs[11]); | ||
| 179 | printk(" " FOURLONG, | ||
| 180 | regs->gprs[12], regs->gprs[13], regs->gprs[14], regs->gprs[15]); | ||
| 181 | show_code(regs); | ||
| 182 | } | ||
| 183 | |||
| 184 | void show_regs(struct pt_regs *regs) | ||
| 185 | { | ||
| 186 | printk("CPU: %d %s %s %.*s\n", | ||
| 187 | task_thread_info(current)->cpu, print_tainted(), | ||
| 188 | init_utsname()->release, | ||
| 189 | (int)strcspn(init_utsname()->version, " "), | ||
| 190 | init_utsname()->version); | ||
| 191 | printk("Process %s (pid: %d, task: %p, ksp: %p)\n", | ||
| 192 | current->comm, current->pid, current, | ||
| 193 | (void *) current->thread.ksp); | ||
| 194 | show_registers(regs); | ||
| 195 | /* Show stack backtrace if pt_regs is from kernel mode */ | ||
| 196 | if (!user_mode(regs)) | ||
| 197 | show_trace(NULL, (unsigned long *) regs->gprs[15]); | ||
| 198 | show_last_breaking_event(regs); | ||
| 199 | } | ||
| 200 | |||
| 201 | static DEFINE_SPINLOCK(die_lock); | ||
| 202 | |||
| 203 | void die(struct pt_regs *regs, const char *str) | ||
| 204 | { | ||
| 205 | static int die_counter; | ||
| 206 | |||
| 207 | oops_enter(); | ||
| 208 | lgr_info_log(); | ||
| 209 | debug_stop_all(); | ||
| 210 | console_verbose(); | ||
| 211 | spin_lock_irq(&die_lock); | ||
| 212 | bust_spinlocks(1); | ||
| 213 | printk("%s: %04x [#%d] ", str, regs->int_code & 0xffff, ++die_counter); | ||
| 214 | #ifdef CONFIG_PREEMPT | ||
| 215 | printk("PREEMPT "); | ||
| 216 | #endif | ||
| 217 | #ifdef CONFIG_SMP | ||
| 218 | printk("SMP "); | ||
| 219 | #endif | ||
| 220 | #ifdef CONFIG_DEBUG_PAGEALLOC | ||
| 221 | printk("DEBUG_PAGEALLOC"); | ||
| 222 | #endif | ||
| 223 | printk("\n"); | ||
| 224 | notify_die(DIE_OOPS, str, regs, 0, regs->int_code & 0xffff, SIGSEGV); | ||
| 225 | print_modules(); | ||
| 226 | show_regs(regs); | ||
| 227 | bust_spinlocks(0); | ||
| 228 | add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE); | ||
| 229 | spin_unlock_irq(&die_lock); | ||
| 230 | if (in_interrupt()) | ||
| 231 | panic("Fatal exception in interrupt"); | ||
| 232 | if (panic_on_oops) | ||
| 233 | panic("Fatal exception: panic_on_oops"); | ||
| 234 | oops_exit(); | ||
| 235 | do_exit(SIGSEGV); | ||
| 236 | } | ||
diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c index 13dd63fba367..c5762324d9ee 100644 --- a/arch/s390/kernel/traps.c +++ b/arch/s390/kernel/traps.c | |||
| @@ -12,49 +12,16 @@ | |||
| 12 | * 'Traps.c' handles hardware traps and faults after we have saved some | 12 | * 'Traps.c' handles hardware traps and faults after we have saved some |
| 13 | * state in 'asm.s'. | 13 | * state in 'asm.s'. |
| 14 | */ | 14 | */ |
| 15 | #include <linux/sched.h> | 15 | #include <linux/kprobes.h> |
| 16 | #include <linux/kernel.h> | 16 | #include <linux/kdebug.h> |
| 17 | #include <linux/string.h> | 17 | #include <linux/module.h> |
| 18 | #include <linux/errno.h> | ||
| 19 | #include <linux/ptrace.h> | 18 | #include <linux/ptrace.h> |
| 20 | #include <linux/timer.h> | 19 | #include <linux/sched.h> |
| 21 | #include <linux/mm.h> | 20 | #include <linux/mm.h> |
| 22 | #include <linux/smp.h> | ||
| 23 | #include <linux/init.h> | ||
| 24 | #include <linux/interrupt.h> | ||
| 25 | #include <linux/seq_file.h> | ||
| 26 | #include <linux/delay.h> | ||
| 27 | #include <linux/module.h> | ||
| 28 | #include <linux/kdebug.h> | ||
| 29 | #include <linux/kallsyms.h> | ||
| 30 | #include <linux/reboot.h> | ||
| 31 | #include <linux/kprobes.h> | ||
| 32 | #include <linux/bug.h> | ||
| 33 | #include <linux/utsname.h> | ||
| 34 | #include <asm/uaccess.h> | ||
| 35 | #include <asm/io.h> | ||
| 36 | #include <linux/atomic.h> | ||
| 37 | #include <asm/mathemu.h> | ||
| 38 | #include <asm/cpcmd.h> | ||
| 39 | #include <asm/lowcore.h> | ||
| 40 | #include <asm/debug.h> | ||
| 41 | #include <asm/ipl.h> | ||
| 42 | #include "entry.h" | 21 | #include "entry.h" |
| 43 | 22 | ||
| 44 | int show_unhandled_signals = 1; | 23 | int show_unhandled_signals = 1; |
| 45 | 24 | ||
| 46 | #define stack_pointer ({ void **sp; asm("la %0,0(15)" : "=&d" (sp)); sp; }) | ||
| 47 | |||
| 48 | #ifndef CONFIG_64BIT | ||
| 49 | #define LONG "%08lx " | ||
| 50 | #define FOURLONG "%08lx %08lx %08lx %08lx\n" | ||
| 51 | static int kstack_depth_to_print = 12; | ||
| 52 | #else /* CONFIG_64BIT */ | ||
| 53 | #define LONG "%016lx " | ||
| 54 | #define FOURLONG "%016lx %016lx %016lx %016lx\n" | ||
| 55 | static int kstack_depth_to_print = 20; | ||
| 56 | #endif /* CONFIG_64BIT */ | ||
| 57 | |||
| 58 | static inline void __user *get_trap_ip(struct pt_regs *regs) | 25 | static inline void __user *get_trap_ip(struct pt_regs *regs) |
| 59 | { | 26 | { |
| 60 | #ifdef CONFIG_64BIT | 27 | #ifdef CONFIG_64BIT |
| @@ -72,215 +39,6 @@ static inline void __user *get_trap_ip(struct pt_regs *regs) | |||
| 72 | #endif | 39 | #endif |
| 73 | } | 40 | } |
| 74 | 41 | ||
| 75 | /* | ||
| 76 | * For show_trace we have tree different stack to consider: | ||
| 77 | * - the panic stack which is used if the kernel stack has overflown | ||
| 78 | * - the asynchronous interrupt stack (cpu related) | ||
| 79 | * - the synchronous kernel stack (process related) | ||
| 80 | * The stack trace can start at any of the three stack and can potentially | ||
| 81 | * touch all of them. The order is: panic stack, async stack, sync stack. | ||
| 82 | */ | ||
| 83 | static unsigned long | ||
| 84 | __show_trace(unsigned long sp, unsigned long low, unsigned long high) | ||
| 85 | { | ||
| 86 | struct stack_frame *sf; | ||
| 87 | struct pt_regs *regs; | ||
| 88 | |||
| 89 | while (1) { | ||
| 90 | sp = sp & PSW_ADDR_INSN; | ||
| 91 | if (sp < low || sp > high - sizeof(*sf)) | ||
| 92 | return sp; | ||
| 93 | sf = (struct stack_frame *) sp; | ||
| 94 | printk("([<%016lx>] ", sf->gprs[8] & PSW_ADDR_INSN); | ||
| 95 | print_symbol("%s)\n", sf->gprs[8] & PSW_ADDR_INSN); | ||
| 96 | /* Follow the backchain. */ | ||
| 97 | while (1) { | ||
| 98 | low = sp; | ||
| 99 | sp = sf->back_chain & PSW_ADDR_INSN; | ||
| 100 | if (!sp) | ||
| 101 | break; | ||
| 102 | if (sp <= low || sp > high - sizeof(*sf)) | ||
| 103 | return sp; | ||
| 104 | sf = (struct stack_frame *) sp; | ||
| 105 | printk(" [<%016lx>] ", sf->gprs[8] & PSW_ADDR_INSN); | ||
| 106 | print_symbol("%s\n", sf->gprs[8] & PSW_ADDR_INSN); | ||
| 107 | } | ||
| 108 | /* Zero backchain detected, check for interrupt frame. */ | ||
| 109 | sp = (unsigned long) (sf + 1); | ||
| 110 | if (sp <= low || sp > high - sizeof(*regs)) | ||
| 111 | return sp; | ||
| 112 | regs = (struct pt_regs *) sp; | ||
| 113 | printk(" [<%016lx>] ", regs->psw.addr & PSW_ADDR_INSN); | ||
| 114 | print_symbol("%s\n", regs->psw.addr & PSW_ADDR_INSN); | ||
| 115 | low = sp; | ||
| 116 | sp = regs->gprs[15]; | ||
| 117 | } | ||
| 118 | } | ||
| 119 | |||
| 120 | static void show_trace(struct task_struct *task, unsigned long *stack) | ||
| 121 | { | ||
| 122 | register unsigned long __r15 asm ("15"); | ||
| 123 | unsigned long sp; | ||
| 124 | |||
| 125 | sp = (unsigned long) stack; | ||
| 126 | if (!sp) | ||
| 127 | sp = task ? task->thread.ksp : __r15; | ||
| 128 | printk("Call Trace:\n"); | ||
| 129 | #ifdef CONFIG_CHECK_STACK | ||
| 130 | sp = __show_trace(sp, S390_lowcore.panic_stack - 4096, | ||
| 131 | S390_lowcore.panic_stack); | ||
| 132 | #endif | ||
| 133 | sp = __show_trace(sp, S390_lowcore.async_stack - ASYNC_SIZE, | ||
| 134 | S390_lowcore.async_stack); | ||
| 135 | if (task) | ||
| 136 | __show_trace(sp, (unsigned long) task_stack_page(task), | ||
| 137 | (unsigned long) task_stack_page(task) + THREAD_SIZE); | ||
| 138 | else | ||
| 139 | __show_trace(sp, S390_lowcore.thread_info, | ||
| 140 | S390_lowcore.thread_info + THREAD_SIZE); | ||
| 141 | if (!task) | ||
| 142 | task = current; | ||
| 143 | debug_show_held_locks(task); | ||
| 144 | } | ||
| 145 | |||
| 146 | void show_stack(struct task_struct *task, unsigned long *sp) | ||
| 147 | { | ||
| 148 | register unsigned long * __r15 asm ("15"); | ||
| 149 | unsigned long *stack; | ||
| 150 | int i; | ||
| 151 | |||
| 152 | if (!sp) | ||
| 153 | stack = task ? (unsigned long *) task->thread.ksp : __r15; | ||
| 154 | else | ||
| 155 | stack = sp; | ||
| 156 | |||
| 157 | for (i = 0; i < kstack_depth_to_print; i++) { | ||
| 158 | if (((addr_t) stack & (THREAD_SIZE-1)) == 0) | ||
| 159 | break; | ||
| 160 | if ((i * sizeof(long) % 32) == 0) | ||
| 161 | printk("%s ", i == 0 ? "" : "\n"); | ||
| 162 | printk(LONG, *stack++); | ||
| 163 | } | ||
| 164 | printk("\n"); | ||
| 165 | show_trace(task, sp); | ||
| 166 | } | ||
| 167 | |||
| 168 | static void show_last_breaking_event(struct pt_regs *regs) | ||
| 169 | { | ||
| 170 | #ifdef CONFIG_64BIT | ||
| 171 | printk("Last Breaking-Event-Address:\n"); | ||
| 172 | printk(" [<%016lx>] ", regs->args[0] & PSW_ADDR_INSN); | ||
| 173 | print_symbol("%s\n", regs->args[0] & PSW_ADDR_INSN); | ||
| 174 | #endif | ||
| 175 | } | ||
| 176 | |||
| 177 | /* | ||
| 178 | * The architecture-independent dump_stack generator | ||
| 179 | */ | ||
| 180 | void dump_stack(void) | ||
| 181 | { | ||
| 182 | printk("CPU: %d %s %s %.*s\n", | ||
| 183 | task_thread_info(current)->cpu, print_tainted(), | ||
| 184 | init_utsname()->release, | ||
| 185 | (int)strcspn(init_utsname()->version, " "), | ||
| 186 | init_utsname()->version); | ||
| 187 | printk("Process %s (pid: %d, task: %p, ksp: %p)\n", | ||
| 188 | current->comm, current->pid, current, | ||
| 189 | (void *) current->thread.ksp); | ||
| 190 | show_stack(NULL, NULL); | ||
| 191 | } | ||
| 192 | EXPORT_SYMBOL(dump_stack); | ||
| 193 | |||
| 194 | static inline int mask_bits(struct pt_regs *regs, unsigned long bits) | ||
| 195 | { | ||
| 196 | return (regs->psw.mask & bits) / ((~bits + 1) & bits); | ||
| 197 | } | ||
| 198 | |||
| 199 | void show_registers(struct pt_regs *regs) | ||
| 200 | { | ||
| 201 | char *mode; | ||
| 202 | |||
| 203 | mode = user_mode(regs) ? "User" : "Krnl"; | ||
| 204 | printk("%s PSW : %p %p", | ||
| 205 | mode, (void *) regs->psw.mask, | ||
| 206 | (void *) regs->psw.addr); | ||
| 207 | print_symbol(" (%s)\n", regs->psw.addr & PSW_ADDR_INSN); | ||
| 208 | printk(" R:%x T:%x IO:%x EX:%x Key:%x M:%x W:%x " | ||
| 209 | "P:%x AS:%x CC:%x PM:%x", mask_bits(regs, PSW_MASK_PER), | ||
| 210 | mask_bits(regs, PSW_MASK_DAT), mask_bits(regs, PSW_MASK_IO), | ||
| 211 | mask_bits(regs, PSW_MASK_EXT), mask_bits(regs, PSW_MASK_KEY), | ||
| 212 | mask_bits(regs, PSW_MASK_MCHECK), mask_bits(regs, PSW_MASK_WAIT), | ||
| 213 | mask_bits(regs, PSW_MASK_PSTATE), mask_bits(regs, PSW_MASK_ASC), | ||
| 214 | mask_bits(regs, PSW_MASK_CC), mask_bits(regs, PSW_MASK_PM)); | ||
| 215 | #ifdef CONFIG_64BIT | ||
| 216 | printk(" EA:%x", mask_bits(regs, PSW_MASK_EA | PSW_MASK_BA)); | ||
| 217 | #endif | ||
| 218 | printk("\n%s GPRS: " FOURLONG, mode, | ||
| 219 | regs->gprs[0], regs->gprs[1], regs->gprs[2], regs->gprs[3]); | ||
| 220 | printk(" " FOURLONG, | ||
| 221 | regs->gprs[4], regs->gprs[5], regs->gprs[6], regs->gprs[7]); | ||
| 222 | printk(" " FOURLONG, | ||
| 223 | regs->gprs[8], regs->gprs[9], regs->gprs[10], regs->gprs[11]); | ||
| 224 | printk(" " FOURLONG, | ||
| 225 | regs->gprs[12], regs->gprs[13], regs->gprs[14], regs->gprs[15]); | ||
| 226 | |||
| 227 | show_code(regs); | ||
| 228 | } | ||
| 229 | |||
| 230 | void show_regs(struct pt_regs *regs) | ||
| 231 | { | ||
| 232 | printk("CPU: %d %s %s %.*s\n", | ||
| 233 | task_thread_info(current)->cpu, print_tainted(), | ||
| 234 | init_utsname()->release, | ||
| 235 | (int)strcspn(init_utsname()->version, " "), | ||
| 236 | init_utsname()->version); | ||
| 237 | printk("Process %s (pid: %d, task: %p, ksp: %p)\n", | ||
| 238 | current->comm, current->pid, current, | ||
| 239 | (void *) current->thread.ksp); | ||
| 240 | show_registers(regs); | ||
| 241 | /* Show stack backtrace if pt_regs is from kernel mode */ | ||
| 242 | if (!user_mode(regs)) | ||
| 243 | show_trace(NULL, (unsigned long *) regs->gprs[15]); | ||
| 244 | show_last_breaking_event(regs); | ||
| 245 | } | ||
| 246 | |||
| 247 | static DEFINE_SPINLOCK(die_lock); | ||
| 248 | |||
| 249 | void die(struct pt_regs *regs, const char *str) | ||
| 250 | { | ||
| 251 | static int die_counter; | ||
| 252 | |||
| 253 | oops_enter(); | ||
| 254 | lgr_info_log(); | ||
| 255 | debug_stop_all(); | ||
| 256 | console_verbose(); | ||
| 257 | spin_lock_irq(&die_lock); | ||
| 258 | bust_spinlocks(1); | ||
| 259 | printk("%s: %04x [#%d] ", str, regs->int_code & 0xffff, ++die_counter); | ||
| 260 | #ifdef CONFIG_PREEMPT | ||
| 261 | printk("PREEMPT "); | ||
| 262 | #endif | ||
| 263 | #ifdef CONFIG_SMP | ||
| 264 | printk("SMP "); | ||
| 265 | #endif | ||
| 266 | #ifdef CONFIG_DEBUG_PAGEALLOC | ||
| 267 | printk("DEBUG_PAGEALLOC"); | ||
| 268 | #endif | ||
| 269 | printk("\n"); | ||
| 270 | notify_die(DIE_OOPS, str, regs, 0, regs->int_code & 0xffff, SIGSEGV); | ||
| 271 | print_modules(); | ||
| 272 | show_regs(regs); | ||
| 273 | bust_spinlocks(0); | ||
| 274 | add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE); | ||
| 275 | spin_unlock_irq(&die_lock); | ||
| 276 | if (in_interrupt()) | ||
| 277 | panic("Fatal exception in interrupt"); | ||
| 278 | if (panic_on_oops) | ||
| 279 | panic("Fatal exception: panic_on_oops"); | ||
| 280 | oops_exit(); | ||
| 281 | do_exit(SIGSEGV); | ||
| 282 | } | ||
| 283 | |||
| 284 | static inline void report_user_fault(struct pt_regs *regs, int signr) | 42 | static inline void report_user_fault(struct pt_regs *regs, int signr) |
| 285 | { | 43 | { |
| 286 | if ((task_pid_nr(current) > 1) && !show_unhandled_signals) | 44 | if ((task_pid_nr(current) > 1) && !show_unhandled_signals) |
