aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm/Kconfig4
-rw-r--r--arch/arm/include/asm/bug.h55
-rw-r--r--arch/arm/kernel/traps.c31
-rw-r--r--arch/arm/kernel/vmlinux.lds.S3
4 files changed, 73 insertions, 20 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 3269576dbfa8..1412da8ccf05 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -215,6 +215,10 @@ config ARM_PATCH_PHYS_VIRT_16BIT
215 to allow physical memory down to a theoretical minimum of 64K 215 to allow physical memory down to a theoretical minimum of 64K
216 boundaries. 216 boundaries.
217 217
218config GENERIC_BUG
219 def_bool y
220 depends on BUG
221
218source "init/Kconfig" 222source "init/Kconfig"
219 223
220source "kernel/Kconfig.freezer" 224source "kernel/Kconfig.freezer"
diff --git a/arch/arm/include/asm/bug.h b/arch/arm/include/asm/bug.h
index 4d88425a4169..9abe7a07d5ac 100644
--- a/arch/arm/include/asm/bug.h
+++ b/arch/arm/include/asm/bug.h
@@ -3,21 +3,58 @@
3 3
4 4
5#ifdef CONFIG_BUG 5#ifdef CONFIG_BUG
6#ifdef CONFIG_DEBUG_BUGVERBOSE
7extern void __bug(const char *file, int line) __attribute__((noreturn));
8
9/* give file/line information */
10#define BUG() __bug(__FILE__, __LINE__)
11 6
7/*
8 * Use a suitable undefined instruction to use for ARM/Thumb2 bug handling.
9 * We need to be careful not to conflict with those used by other modules and
10 * the register_undef_hook() system.
11 */
12#ifdef CONFIG_THUMB2_KERNEL
13#define BUG_INSTR_VALUE 0xde02
14#define BUG_INSTR_TYPE ".hword "
12#else 15#else
16#define BUG_INSTR_VALUE 0xe7f001f2
17#define BUG_INSTR_TYPE ".word "
18#endif
13 19
14/* this just causes an oops */
15#define BUG() do { *(int *)0 = 0; } while (1)
16 20
17#endif 21#define BUG() _BUG(__FILE__, __LINE__, BUG_INSTR_VALUE)
22#define _BUG(file, line, value) __BUG(file, line, value)
23
24#ifdef CONFIG_DEBUG_BUGVERBOSE
25
26/*
27 * The extra indirection is to ensure that the __FILE__ string comes through
28 * OK. Many version of gcc do not support the asm %c parameter which would be
29 * preferable to this unpleasantness. We use mergeable string sections to
30 * avoid multiple copies of the string appearing in the kernel image.
31 */
32
33#define __BUG(__file, __line, __value) \
34do { \
35 BUILD_BUG_ON(sizeof(struct bug_entry) != 12); \
36 asm volatile("1:\t" BUG_INSTR_TYPE #__value "\n" \
37 ".pushsection .rodata.str, \"aMS\", %progbits, 1\n" \
38 "2:\t.asciz " #__file "\n" \
39 ".popsection\n" \
40 ".pushsection __bug_table,\"a\"\n" \
41 "3:\t.word 1b, 2b\n" \
42 "\t.hword " #__line ", 0\n" \
43 ".popsection"); \
44 unreachable(); \
45} while (0)
46
47#else /* not CONFIG_DEBUG_BUGVERBOSE */
48
49#define __BUG(__file, __line, __value) \
50do { \
51 asm volatile(BUG_INSTR_TYPE #__value); \
52 unreachable(); \
53} while (0)
54#endif /* CONFIG_DEBUG_BUGVERBOSE */
18 55
19#define HAVE_ARCH_BUG 56#define HAVE_ARCH_BUG
20#endif 57#endif /* CONFIG_BUG */
21 58
22#include <asm-generic/bug.h> 59#include <asm-generic/bug.h>
23 60
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index bc9f9da782cb..74969248c375 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -21,6 +21,7 @@
21#include <linux/kdebug.h> 21#include <linux/kdebug.h>
22#include <linux/module.h> 22#include <linux/module.h>
23#include <linux/kexec.h> 23#include <linux/kexec.h>
24#include <linux/bug.h>
24#include <linux/delay.h> 25#include <linux/delay.h>
25#include <linux/init.h> 26#include <linux/init.h>
26#include <linux/sched.h> 27#include <linux/sched.h>
@@ -270,6 +271,8 @@ void die(const char *str, struct pt_regs *regs, int err)
270 spin_lock_irq(&die_lock); 271 spin_lock_irq(&die_lock);
271 console_verbose(); 272 console_verbose();
272 bust_spinlocks(1); 273 bust_spinlocks(1);
274 if (!user_mode(regs))
275 report_bug(regs->ARM_pc, regs);
273 ret = __die(str, err, thread, regs); 276 ret = __die(str, err, thread, regs);
274 277
275 if (regs && kexec_should_crash(thread->task)) 278 if (regs && kexec_should_crash(thread->task))
@@ -301,6 +304,24 @@ void arm_notify_die(const char *str, struct pt_regs *regs,
301 } 304 }
302} 305}
303 306
307#ifdef CONFIG_GENERIC_BUG
308
309int is_valid_bugaddr(unsigned long pc)
310{
311#ifdef CONFIG_THUMB2_KERNEL
312 unsigned short bkpt;
313#else
314 unsigned long bkpt;
315#endif
316
317 if (probe_kernel_address((unsigned *)pc, bkpt))
318 return 0;
319
320 return bkpt == BUG_INSTR_VALUE;
321}
322
323#endif
324
304static LIST_HEAD(undef_hook); 325static LIST_HEAD(undef_hook);
305static DEFINE_SPINLOCK(undef_lock); 326static DEFINE_SPINLOCK(undef_lock);
306 327
@@ -706,16 +727,6 @@ baddataabort(int code, unsigned long instr, struct pt_regs *regs)
706 arm_notify_die("unknown data abort code", regs, &info, instr, 0); 727 arm_notify_die("unknown data abort code", regs, &info, instr, 0);
707} 728}
708 729
709void __attribute__((noreturn)) __bug(const char *file, int line)
710{
711 printk(KERN_CRIT"kernel BUG at %s:%d!\n", file, line);
712 *(int *)0 = 0;
713
714 /* Avoid "noreturn function does return" */
715 for (;;);
716}
717EXPORT_SYMBOL(__bug);
718
719void __readwrite_bug(const char *fn) 730void __readwrite_bug(const char *fn)
720{ 731{
721 printk("%s called, but not implemented\n", fn); 732 printk("%s called, but not implemented\n", fn);
diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S
index bf977f8514f6..7b2541efd9f8 100644
--- a/arch/arm/kernel/vmlinux.lds.S
+++ b/arch/arm/kernel/vmlinux.lds.S
@@ -21,7 +21,8 @@
21#define ARM_CPU_KEEP(x) 21#define ARM_CPU_KEEP(x)
22#endif 22#endif
23 23
24#if defined(CONFIG_SMP_ON_UP) && !defined(CONFIG_DEBUG_SPINLOCK) 24#if (defined(CONFIG_SMP_ON_UP) && !defined(CONFIG_DEBUG_SPINLOCK)) || \
25 defined(CONFIG_GENERIC_BUG)
25#define ARM_EXIT_KEEP(x) x 26#define ARM_EXIT_KEEP(x) x
26#else 27#else
27#define ARM_EXIT_KEEP(x) 28#define ARM_EXIT_KEEP(x)