diff options
Diffstat (limited to 'arch/arm/kernel/traps.c')
| -rw-r--r-- | arch/arm/kernel/traps.c | 76 | 
1 files changed, 41 insertions, 35 deletions
| diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index 467b69ed1021..f838f36eb702 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c | |||
| @@ -45,21 +45,21 @@ static int __init user_debug_setup(char *str) | |||
| 45 | __setup("user_debug=", user_debug_setup); | 45 | __setup("user_debug=", user_debug_setup); | 
| 46 | #endif | 46 | #endif | 
| 47 | 47 | ||
| 48 | static void dump_mem(const char *str, unsigned long bottom, unsigned long top); | 48 | static void dump_mem(const char *, const char *, unsigned long, unsigned long); | 
| 49 | 49 | ||
| 50 | void dump_backtrace_entry(unsigned long where, unsigned long from, unsigned long frame) | 50 | void dump_backtrace_entry(unsigned long where, unsigned long from, unsigned long frame) | 
| 51 | { | 51 | { | 
| 52 | #ifdef CONFIG_KALLSYMS | 52 | #ifdef CONFIG_KALLSYMS | 
| 53 | printk("[<%08lx>] ", where); | 53 | char sym1[KSYM_SYMBOL_LEN], sym2[KSYM_SYMBOL_LEN]; | 
| 54 | print_symbol("(%s) ", where); | 54 | sprint_symbol(sym1, where); | 
| 55 | printk("from [<%08lx>] ", from); | 55 | sprint_symbol(sym2, from); | 
| 56 | print_symbol("(%s)\n", from); | 56 | printk("[<%08lx>] (%s) from [<%08lx>] (%s)\n", where, sym1, from, sym2); | 
| 57 | #else | 57 | #else | 
| 58 | printk("Function entered at [<%08lx>] from [<%08lx>]\n", where, from); | 58 | printk("Function entered at [<%08lx>] from [<%08lx>]\n", where, from); | 
| 59 | #endif | 59 | #endif | 
| 60 | 60 | ||
| 61 | if (in_exception_text(where)) | 61 | if (in_exception_text(where)) | 
| 62 | dump_mem("Exception stack", frame + 4, frame + 4 + sizeof(struct pt_regs)); | 62 | dump_mem("", "Exception stack", frame + 4, frame + 4 + sizeof(struct pt_regs)); | 
| 63 | } | 63 | } | 
| 64 | 64 | ||
| 65 | #ifndef CONFIG_ARM_UNWIND | 65 | #ifndef CONFIG_ARM_UNWIND | 
| @@ -81,9 +81,10 @@ static int verify_stack(unsigned long sp) | |||
| 81 | /* | 81 | /* | 
| 82 | * Dump out the contents of some memory nicely... | 82 | * Dump out the contents of some memory nicely... | 
| 83 | */ | 83 | */ | 
| 84 | static void dump_mem(const char *str, unsigned long bottom, unsigned long top) | 84 | static void dump_mem(const char *lvl, const char *str, unsigned long bottom, | 
| 85 | unsigned long top) | ||
| 85 | { | 86 | { | 
| 86 | unsigned long p = bottom & ~31; | 87 | unsigned long first; | 
| 87 | mm_segment_t fs; | 88 | mm_segment_t fs; | 
| 88 | int i; | 89 | int i; | 
| 89 | 90 | ||
| @@ -95,33 +96,37 @@ static void dump_mem(const char *str, unsigned long bottom, unsigned long top) | |||
| 95 | fs = get_fs(); | 96 | fs = get_fs(); | 
| 96 | set_fs(KERNEL_DS); | 97 | set_fs(KERNEL_DS); | 
| 97 | 98 | ||
| 98 | printk("%s(0x%08lx to 0x%08lx)\n", str, bottom, top); | 99 | printk("%s%s(0x%08lx to 0x%08lx)\n", lvl, str, bottom, top); | 
| 99 | 100 | ||
| 100 | for (p = bottom & ~31; p < top;) { | 101 | for (first = bottom & ~31; first < top; first += 32) { | 
| 101 | printk("%04lx: ", p & 0xffff); | 102 | unsigned long p; | 
| 103 | char str[sizeof(" 12345678") * 8 + 1]; | ||
| 102 | 104 | ||
| 103 | for (i = 0; i < 8; i++, p += 4) { | 105 | memset(str, ' ', sizeof(str)); | 
| 104 | unsigned int val; | 106 | str[sizeof(str) - 1] = '\0'; | 
| 105 | 107 | ||
| 106 | if (p < bottom || p >= top) | 108 | for (p = first, i = 0; i < 8 && p < top; i++, p += 4) { | 
| 107 | printk(" "); | 109 | if (p >= bottom && p < top) { | 
| 108 | else { | 110 | unsigned long val; | 
| 109 | __get_user(val, (unsigned long *)p); | 111 | if (__get_user(val, (unsigned long *)p) == 0) | 
| 110 | printk("%08x ", val); | 112 | sprintf(str + i * 9, " %08lx", val); | 
| 113 | else | ||
| 114 | sprintf(str + i * 9, " ????????"); | ||
| 111 | } | 115 | } | 
| 112 | } | 116 | } | 
| 113 | printk ("\n"); | 117 | printk("%s%04lx:%s\n", lvl, first & 0xffff, str); | 
| 114 | } | 118 | } | 
| 115 | 119 | ||
| 116 | set_fs(fs); | 120 | set_fs(fs); | 
| 117 | } | 121 | } | 
| 118 | 122 | ||
| 119 | static void dump_instr(struct pt_regs *regs) | 123 | static void dump_instr(const char *lvl, struct pt_regs *regs) | 
| 120 | { | 124 | { | 
| 121 | unsigned long addr = instruction_pointer(regs); | 125 | unsigned long addr = instruction_pointer(regs); | 
| 122 | const int thumb = thumb_mode(regs); | 126 | const int thumb = thumb_mode(regs); | 
| 123 | const int width = thumb ? 4 : 8; | 127 | const int width = thumb ? 4 : 8; | 
| 124 | mm_segment_t fs; | 128 | mm_segment_t fs; | 
| 129 | char str[sizeof("00000000 ") * 5 + 2 + 1], *p = str; | ||
| 125 | int i; | 130 | int i; | 
| 126 | 131 | ||
| 127 | /* | 132 | /* | 
| @@ -132,7 +137,6 @@ static void dump_instr(struct pt_regs *regs) | |||
| 132 | fs = get_fs(); | 137 | fs = get_fs(); | 
| 133 | set_fs(KERNEL_DS); | 138 | set_fs(KERNEL_DS); | 
| 134 | 139 | ||
| 135 | printk("Code: "); | ||
| 136 | for (i = -4; i < 1; i++) { | 140 | for (i = -4; i < 1; i++) { | 
| 137 | unsigned int val, bad; | 141 | unsigned int val, bad; | 
| 138 | 142 | ||
| @@ -142,13 +146,14 @@ static void dump_instr(struct pt_regs *regs) | |||
| 142 | bad = __get_user(val, &((u32 *)addr)[i]); | 146 | bad = __get_user(val, &((u32 *)addr)[i]); | 
| 143 | 147 | ||
| 144 | if (!bad) | 148 | if (!bad) | 
| 145 | printk(i == 0 ? "(%0*x) " : "%0*x ", width, val); | 149 | p += sprintf(p, i == 0 ? "(%0*x) " : "%0*x ", | 
| 150 | width, val); | ||
| 146 | else { | 151 | else { | 
| 147 | printk("bad PC value."); | 152 | p += sprintf(p, "bad PC value"); | 
| 148 | break; | 153 | break; | 
| 149 | } | 154 | } | 
| 150 | } | 155 | } | 
| 151 | printk("\n"); | 156 | printk("%sCode: %s\n", lvl, str); | 
| 152 | 157 | ||
| 153 | set_fs(fs); | 158 | set_fs(fs); | 
| 154 | } | 159 | } | 
| @@ -224,18 +229,19 @@ static void __die(const char *str, int err, struct thread_info *thread, struct p | |||
| 224 | struct task_struct *tsk = thread->task; | 229 | struct task_struct *tsk = thread->task; | 
| 225 | static int die_counter; | 230 | static int die_counter; | 
| 226 | 231 | ||
| 227 | printk("Internal error: %s: %x [#%d]" S_PREEMPT S_SMP "\n", | 232 | printk(KERN_EMERG "Internal error: %s: %x [#%d]" S_PREEMPT S_SMP "\n", | 
| 228 | str, err, ++die_counter); | 233 | str, err, ++die_counter); | 
| 234 | sysfs_printk_last_file(); | ||
| 229 | print_modules(); | 235 | print_modules(); | 
| 230 | __show_regs(regs); | 236 | __show_regs(regs); | 
| 231 | printk("Process %s (pid: %d, stack limit = 0x%p)\n", | 237 | printk(KERN_EMERG "Process %.*s (pid: %d, stack limit = 0x%p)\n", | 
| 232 | tsk->comm, task_pid_nr(tsk), thread + 1); | 238 | TASK_COMM_LEN, tsk->comm, task_pid_nr(tsk), thread + 1); | 
| 233 | 239 | ||
| 234 | if (!user_mode(regs) || in_interrupt()) { | 240 | if (!user_mode(regs) || in_interrupt()) { | 
| 235 | dump_mem("Stack: ", regs->ARM_sp, | 241 | dump_mem(KERN_EMERG, "Stack: ", regs->ARM_sp, | 
| 236 | THREAD_SIZE + (unsigned long)task_stack_page(tsk)); | 242 | THREAD_SIZE + (unsigned long)task_stack_page(tsk)); | 
| 237 | dump_backtrace(regs, tsk); | 243 | dump_backtrace(regs, tsk); | 
| 238 | dump_instr(regs); | 244 | dump_instr(KERN_EMERG, regs); | 
| 239 | } | 245 | } | 
| 240 | } | 246 | } | 
| 241 | 247 | ||
| @@ -250,13 +256,14 @@ NORET_TYPE void die(const char *str, struct pt_regs *regs, int err) | |||
| 250 | 256 | ||
| 251 | oops_enter(); | 257 | oops_enter(); | 
| 252 | 258 | ||
| 253 | console_verbose(); | ||
| 254 | spin_lock_irq(&die_lock); | 259 | spin_lock_irq(&die_lock); | 
| 260 | console_verbose(); | ||
| 255 | bust_spinlocks(1); | 261 | bust_spinlocks(1); | 
| 256 | __die(str, err, thread, regs); | 262 | __die(str, err, thread, regs); | 
| 257 | bust_spinlocks(0); | 263 | bust_spinlocks(0); | 
| 258 | add_taint(TAINT_DIE); | 264 | add_taint(TAINT_DIE); | 
| 259 | spin_unlock_irq(&die_lock); | 265 | spin_unlock_irq(&die_lock); | 
| 266 | oops_exit(); | ||
| 260 | 267 | ||
| 261 | if (in_interrupt()) | 268 | if (in_interrupt()) | 
| 262 | panic("Fatal exception in interrupt"); | 269 | panic("Fatal exception in interrupt"); | 
| @@ -264,7 +271,6 @@ NORET_TYPE void die(const char *str, struct pt_regs *regs, int err) | |||
| 264 | if (panic_on_oops) | 271 | if (panic_on_oops) | 
| 265 | panic("Fatal exception"); | 272 | panic("Fatal exception"); | 
| 266 | 273 | ||
| 267 | oops_exit(); | ||
| 268 | do_exit(SIGSEGV); | 274 | do_exit(SIGSEGV); | 
| 269 | } | 275 | } | 
| 270 | 276 | ||
| @@ -349,7 +355,7 @@ asmlinkage void __exception do_undefinstr(struct pt_regs *regs) | |||
| 349 | if (user_debug & UDBG_UNDEFINED) { | 355 | if (user_debug & UDBG_UNDEFINED) { | 
| 350 | printk(KERN_INFO "%s (%d): undefined instruction: pc=%p\n", | 356 | printk(KERN_INFO "%s (%d): undefined instruction: pc=%p\n", | 
| 351 | current->comm, task_pid_nr(current), pc); | 357 | current->comm, task_pid_nr(current), pc); | 
| 352 | dump_instr(regs); | 358 | dump_instr(KERN_INFO, regs); | 
| 353 | } | 359 | } | 
| 354 | #endif | 360 | #endif | 
| 355 | 361 | ||
| @@ -400,7 +406,7 @@ static int bad_syscall(int n, struct pt_regs *regs) | |||
| 400 | if (user_debug & UDBG_SYSCALL) { | 406 | if (user_debug & UDBG_SYSCALL) { | 
| 401 | printk(KERN_ERR "[%d] %s: obsolete system call %08x.\n", | 407 | printk(KERN_ERR "[%d] %s: obsolete system call %08x.\n", | 
| 402 | task_pid_nr(current), current->comm, n); | 408 | task_pid_nr(current), current->comm, n); | 
| 403 | dump_instr(regs); | 409 | dump_instr(KERN_ERR, regs); | 
| 404 | } | 410 | } | 
| 405 | #endif | 411 | #endif | 
| 406 | 412 | ||
| @@ -579,7 +585,7 @@ asmlinkage int arm_syscall(int no, struct pt_regs *regs) | |||
| 579 | if (user_debug & UDBG_SYSCALL) { | 585 | if (user_debug & UDBG_SYSCALL) { | 
| 580 | printk("[%d] %s: arm syscall %d\n", | 586 | printk("[%d] %s: arm syscall %d\n", | 
| 581 | task_pid_nr(current), current->comm, no); | 587 | task_pid_nr(current), current->comm, no); | 
| 582 | dump_instr(regs); | 588 | dump_instr("", regs); | 
| 583 | if (user_mode(regs)) { | 589 | if (user_mode(regs)) { | 
| 584 | __show_regs(regs); | 590 | __show_regs(regs); | 
| 585 | c_backtrace(regs->ARM_fp, processor_mode(regs)); | 591 | c_backtrace(regs->ARM_fp, processor_mode(regs)); | 
| @@ -656,7 +662,7 @@ baddataabort(int code, unsigned long instr, struct pt_regs *regs) | |||
| 656 | if (user_debug & UDBG_BADABORT) { | 662 | if (user_debug & UDBG_BADABORT) { | 
| 657 | printk(KERN_ERR "[%d] %s: bad data abort: code %d instr 0x%08lx\n", | 663 | printk(KERN_ERR "[%d] %s: bad data abort: code %d instr 0x%08lx\n", | 
| 658 | task_pid_nr(current), current->comm, code, instr); | 664 | task_pid_nr(current), current->comm, code, instr); | 
| 659 | dump_instr(regs); | 665 | dump_instr(KERN_ERR, regs); | 
| 660 | show_pte(current->mm, addr); | 666 | show_pte(current->mm, addr); | 
| 661 | } | 667 | } | 
| 662 | #endif | 668 | #endif | 
