diff --git a/arch/sh/include/asm/bug.h b/arch/sh/include/asm/bug.h index b7d9822fd6c2..23c5504a3a01 100644 --- a/arch/sh/include/asm/bug.h +++ b/arch/sh/include/asm/bug.h @@ -1,8 +1,8 @@ #ifndef __ASM_SH_BUG_H #define __ASM_SH_BUG_H -#define TRAPA_UNWINDER_BUG_OPCODE 0xc33b /* trapa #0x3b */ #define TRAPA_BUG_OPCODE 0xc33e /* trapa #0x3e */ +#define BUGFLAG_UNWINDER (1 << 1) #ifdef CONFIG_GENERIC_BUG #define HAVE_ARCH_BUG @@ -73,15 +73,16 @@ do { \ unlikely(__ret_warn_on); \ }) -#define UNWINDER_BUG() \ +#define UNWINDER_BUG() \ do { \ __asm__ __volatile__ ( \ "1:\t.short %O0\n" \ - _EMIT_BUG_ENTRY \ + _EMIT_BUG_ENTRY \ : \ - : "n" (TRAPA_UNWINDER_BUG_OPCODE), \ + : "n" (TRAPA_BUG_OPCODE), \ "i" (__FILE__), \ - "i" (__LINE__), "i" (0), \ + "i" (__LINE__), \ + "i" (BUGFLAG_UNWINDER), \ "i" (sizeof(struct bug_entry))); \ } while (0) diff --git a/arch/sh/kernel/debugtraps.S b/arch/sh/kernel/debugtraps.S index cb00e4a82d4d..591741383ee6 100644 --- a/arch/sh/kernel/debugtraps.S +++ b/arch/sh/kernel/debugtraps.S @@ -19,10 +19,6 @@ #if !defined(CONFIG_SH_STANDARD_BIOS) #define sh_bios_handler debug_trap_handler -#endif - -#if !defined(CONFIG_DWARF_UNWINDER) -#define unwinder_trap_handler debug_trap_handler #endif .data @@ -39,7 +35,7 @@ ENTRY(debug_trap_table) .long debug_trap_handler /* 0x38 */ .long debug_trap_handler /* 0x39 */ .long debug_trap_handler /* 0x3a */ - .long unwinder_trap_handler /* 0x3b */ + .long debug_trap_handler /* 0x3b */ .long breakpoint_trap_handler /* 0x3c */ .long singlestep_trap_handler /* 0x3d */ .long bug_trap_handler /* 0x3e */ diff --git a/arch/sh/kernel/traps.c b/arch/sh/kernel/traps.c index 881b9a32b7de..f69bd968fcca 100644 --- a/arch/sh/kernel/traps.c +++ b/arch/sh/kernel/traps.c @@ -5,18 +5,32 @@ #include #include #include +#include #include #ifdef CONFIG_BUG void handle_BUG(struct pt_regs *regs) { + const struct bug_entry *bug; + unsigned long bugaddr = regs->pc; enum bug_trap_type tt; - tt = report_bug(regs->pc, regs); + + if (!is_valid_bugaddr(bugaddr)) + goto invalid; + + bug = find_bug(bugaddr); + + /* Switch unwinders when unwind_stack() is called */ + if (bug->flags & BUGFLAG_UNWINDER) + unwinder_faulted = 1; + + tt = report_bug(bugaddr, regs); if (tt == BUG_TRAP_TYPE_WARN) { - regs->pc += instruction_size(regs->pc); + regs->pc += instruction_size(bugaddr); return; } +invalid: die("Kernel BUG", regs, TRAPA_BUG_OPCODE & 0xff); } @@ -28,8 +42,7 @@ int is_valid_bugaddr(unsigned long addr) return 0; if (probe_kernel_address((insn_size_t *)addr, opcode)) return 0; - - if (opcode == TRAPA_BUG_OPCODE || opcode == TRAPA_UNWINDER_BUG_OPCODE) + if (opcode == TRAPA_BUG_OPCODE) return 1; return 0; diff --git a/arch/sh/kernel/unwinder.c b/arch/sh/kernel/unwinder.c index e83861d9739c..468889d958f4 100644 --- a/arch/sh/kernel/unwinder.c +++ b/arch/sh/kernel/unwinder.c @@ -161,25 +161,4 @@ void unwind_stack(struct task_struct *task, struct pt_regs *regs, curr_unwinder->dump(task, regs, sp, ops, data); } - -/* - * Trap handler for UWINDER_BUG() statements. We must switch to the - * unwinder with the next highest rating. - */ -BUILD_TRAP_HANDLER(unwinder) -{ - insn_size_t insn; - TRAP_HANDLER_DECL; - - /* Rewind */ - regs->pc -= instruction_size(ctrl_inw(regs->pc - 4)); - insn = *(insn_size_t *)instruction_pointer(regs); - - /* Switch unwinders when unwind_stack() is called */ - unwinder_faulted = 1; - -#ifdef CONFIG_BUG - handle_BUG(regs); -#endif -} EXPORT_SYMBOL_GPL(unwind_stack);