1 #include <linux/bug.h> 2 #include <linux/io.h> 3 #include <linux/types.h> 4 #include <linux/kdebug.h> 5 #include <linux/signal.h> 6 #include <linux/sched.h> 7 #include <linux/uaccess.h> 8 #include <asm/unwinder.h> 9 #include <asm/system.h> 10 11 #ifdef CONFIG_BUG 12 void handle_BUG(struct pt_regs *regs) 13 { 14 const struct bug_entry *bug; 15 unsigned long bugaddr = regs->pc; 16 enum bug_trap_type tt; 17 18 if (!is_valid_bugaddr(bugaddr)) 19 goto invalid; 20 21 bug = find_bug(bugaddr); 22 23 /* Switch unwinders when unwind_stack() is called */ 24 if (bug->flags & BUGFLAG_UNWINDER) 25 unwinder_faulted = 1; 26 27 tt = report_bug(bugaddr, regs); 28 if (tt == BUG_TRAP_TYPE_WARN) { 29 regs->pc += instruction_size(bugaddr); 30 return; 31 } 32 33 invalid: 34 die("Kernel BUG", regs, TRAPA_BUG_OPCODE & 0xff); 35 } 36 37 int is_valid_bugaddr(unsigned long addr) 38 { 39 insn_size_t opcode; 40 41 if (addr < PAGE_OFFSET) 42 return 0; 43 if (probe_kernel_address((insn_size_t *)addr, opcode)) 44 return 0; 45 if (opcode == TRAPA_BUG_OPCODE) 46 return 1; 47 48 return 0; 49 } 50 #endif 51 52 /* 53 * Generic trap handler. 54 */ 55 BUILD_TRAP_HANDLER(debug) 56 { 57 TRAP_HANDLER_DECL; 58 59 /* Rewind */ 60 regs->pc -= instruction_size(ctrl_inw(regs->pc - 4)); 61 62 if (notify_die(DIE_TRAP, "debug trap", regs, 0, vec & 0xff, 63 SIGTRAP) == NOTIFY_STOP) 64 return; 65 66 force_sig(SIGTRAP, current); 67 } 68 69 /* 70 * Special handler for BUG() traps. 71 */ 72 BUILD_TRAP_HANDLER(bug) 73 { 74 TRAP_HANDLER_DECL; 75 76 /* Rewind */ 77 regs->pc -= instruction_size(ctrl_inw(regs->pc - 4)); 78 79 if (notify_die(DIE_TRAP, "bug trap", regs, 0, TRAPA_BUG_OPCODE & 0xff, 80 SIGTRAP) == NOTIFY_STOP) 81 return; 82 83 #ifdef CONFIG_BUG 84 if (__kernel_text_address(instruction_pointer(regs))) { 85 insn_size_t insn = *(insn_size_t *)instruction_pointer(regs); 86 if (insn == TRAPA_BUG_OPCODE) 87 handle_BUG(regs); 88 return; 89 } 90 #endif 91 92 force_sig(SIGTRAP, current); 93 } 94