diff options
author | Paul Mundt <lethal@linux-sh.org> | 2009-08-21 16:28:25 -0400 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2009-08-21 16:28:25 -0400 |
commit | e115f2c17cbceee93b34d787a7a4a867fc73e7b4 (patch) | |
tree | 6ee0f20dcb5eca29793d68e97242c5e483c24cfc /arch/sh/kernel | |
parent | c153a58e715e16ffcd6c4b3da7fc6b4a556bf917 (diff) |
sh: unwinder: Use a special bug flag for unwinder traps.
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>
Diffstat (limited to 'arch/sh/kernel')
-rw-r--r-- | arch/sh/kernel/debugtraps.S | 6 | ||||
-rw-r--r-- | arch/sh/kernel/traps.c | 21 | ||||
-rw-r--r-- | arch/sh/kernel/unwinder.c | 21 |
3 files changed, 18 insertions, 30 deletions
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 | |||
@@ -21,10 +21,6 @@ | |||
21 | #define sh_bios_handler debug_trap_handler | 21 | #define sh_bios_handler debug_trap_handler |
22 | #endif | 22 | #endif |
23 | 23 | ||
24 | #if !defined(CONFIG_DWARF_UNWINDER) | ||
25 | #define unwinder_trap_handler debug_trap_handler | ||
26 | #endif | ||
27 | |||
28 | .data | 24 | .data |
29 | 25 | ||
30 | ENTRY(debug_trap_table) | 26 | ENTRY(debug_trap_table) |
@@ -39,7 +35,7 @@ ENTRY(debug_trap_table) | |||
39 | .long debug_trap_handler /* 0x38 */ | 35 | .long debug_trap_handler /* 0x38 */ |
40 | .long debug_trap_handler /* 0x39 */ | 36 | .long debug_trap_handler /* 0x39 */ |
41 | .long debug_trap_handler /* 0x3a */ | 37 | .long debug_trap_handler /* 0x3a */ |
42 | .long unwinder_trap_handler /* 0x3b */ | 38 | .long debug_trap_handler /* 0x3b */ |
43 | .long breakpoint_trap_handler /* 0x3c */ | 39 | .long breakpoint_trap_handler /* 0x3c */ |
44 | .long singlestep_trap_handler /* 0x3d */ | 40 | .long singlestep_trap_handler /* 0x3d */ |
45 | .long bug_trap_handler /* 0x3e */ | 41 | .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 @@ | |||
5 | #include <linux/signal.h> | 5 | #include <linux/signal.h> |
6 | #include <linux/sched.h> | 6 | #include <linux/sched.h> |
7 | #include <linux/uaccess.h> | 7 | #include <linux/uaccess.h> |
8 | #include <asm/unwinder.h> | ||
8 | #include <asm/system.h> | 9 | #include <asm/system.h> |
9 | 10 | ||
10 | #ifdef CONFIG_BUG | 11 | #ifdef CONFIG_BUG |
11 | void handle_BUG(struct pt_regs *regs) | 12 | void handle_BUG(struct pt_regs *regs) |
12 | { | 13 | { |
14 | const struct bug_entry *bug; | ||
15 | unsigned long bugaddr = regs->pc; | ||
13 | enum bug_trap_type tt; | 16 | enum bug_trap_type tt; |
14 | tt = report_bug(regs->pc, regs); | 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); | ||
15 | if (tt == BUG_TRAP_TYPE_WARN) { | 28 | if (tt == BUG_TRAP_TYPE_WARN) { |
16 | regs->pc += instruction_size(regs->pc); | 29 | regs->pc += instruction_size(bugaddr); |
17 | return; | 30 | return; |
18 | } | 31 | } |
19 | 32 | ||
33 | invalid: | ||
20 | die("Kernel BUG", regs, TRAPA_BUG_OPCODE & 0xff); | 34 | die("Kernel BUG", regs, TRAPA_BUG_OPCODE & 0xff); |
21 | } | 35 | } |
22 | 36 | ||
@@ -28,8 +42,7 @@ int is_valid_bugaddr(unsigned long addr) | |||
28 | return 0; | 42 | return 0; |
29 | if (probe_kernel_address((insn_size_t *)addr, opcode)) | 43 | if (probe_kernel_address((insn_size_t *)addr, opcode)) |
30 | return 0; | 44 | return 0; |
31 | 45 | if (opcode == TRAPA_BUG_OPCODE) | |
32 | if (opcode == TRAPA_BUG_OPCODE || opcode == TRAPA_UNWINDER_BUG_OPCODE) | ||
33 | return 1; | 46 | return 1; |
34 | 47 | ||
35 | return 0; | 48 | 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, | |||
161 | 161 | ||
162 | curr_unwinder->dump(task, regs, sp, ops, data); | 162 | curr_unwinder->dump(task, regs, sp, ops, data); |
163 | } | 163 | } |
164 | |||
165 | /* | ||
166 | * Trap handler for UWINDER_BUG() statements. We must switch to the | ||
167 | * unwinder with the next highest rating. | ||
168 | */ | ||
169 | BUILD_TRAP_HANDLER(unwinder) | ||
170 | { | ||
171 | insn_size_t insn; | ||
172 | TRAP_HANDLER_DECL; | ||
173 | |||
174 | /* Rewind */ | ||
175 | regs->pc -= instruction_size(ctrl_inw(regs->pc - 4)); | ||
176 | insn = *(insn_size_t *)instruction_pointer(regs); | ||
177 | |||
178 | /* Switch unwinders when unwind_stack() is called */ | ||
179 | unwinder_faulted = 1; | ||
180 | |||
181 | #ifdef CONFIG_BUG | ||
182 | handle_BUG(regs); | ||
183 | #endif | ||
184 | } | ||
185 | EXPORT_SYMBOL_GPL(unwind_stack); | 164 | EXPORT_SYMBOL_GPL(unwind_stack); |