sh: unwinder: Use a special bug flag for unwinder traps.
authorPaul Mundt <lethal@linux-sh.org>
Fri, 21 Aug 2009 20:28:25 +0000 (05:28 +0900)
committerPaul Mundt <lethal@linux-sh.org>
Fri, 21 Aug 2009 20:28:25 +0000 (05:28 +0900)
This simplifies the unwinder trap handling, dropping the use of the
special trapa vector and simply piggybacking on top of the BUG support. A
new BUGFLAG_UNWINDER is added for flagging the unwinder fault, before
continuing on with regular BUG dispatch.

Signed-off-by: Paul Mundt <lethal@linux-sh.org>
arch/sh/include/asm/bug.h
arch/sh/kernel/debugtraps.S
arch/sh/kernel/traps.c
arch/sh/kernel/unwinder.c

index b7d9822..23c5504 100644 (file)
@@ -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)
 
index cb00e4a..5917413 100644 (file)
 
 #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 */
index 881b9a3..f69bd96 100644 (file)
@@ -5,18 +5,32 @@
 #include <linux/signal.h>
 #include <linux/sched.h>
 #include <linux/uaccess.h>
+#include <asm/unwinder.h>
 #include <asm/system.h>
 
 #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;
index e83861d..468889d 100644 (file)
@@ -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);