diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 3269576dbfa8dab12d6531996e2e86de2ca309c1..1412da8ccf0599bea78497e10d2a6f138de60ef3 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -215,6 +215,10 @@ config ARM_PATCH_PHYS_VIRT_16BIT to allow physical memory down to a theoretical minimum of 64K boundaries. +config GENERIC_BUG + def_bool y + depends on BUG + source "init/Kconfig" source "kernel/Kconfig.freezer" diff --git a/arch/arm/include/asm/bug.h b/arch/arm/include/asm/bug.h index 4d88425a41693e3778a62250bf09eac6446b1d3d..9abe7a07d5acdde3eea377cda3634e5f5c838115 100644 --- a/arch/arm/include/asm/bug.h +++ b/arch/arm/include/asm/bug.h @@ -3,21 +3,58 @@ #ifdef CONFIG_BUG -#ifdef CONFIG_DEBUG_BUGVERBOSE -extern void __bug(const char *file, int line) __attribute__((noreturn)); - -/* give file/line information */ -#define BUG() __bug(__FILE__, __LINE__) +/* + * Use a suitable undefined instruction to use for ARM/Thumb2 bug handling. + * We need to be careful not to conflict with those used by other modules and + * the register_undef_hook() system. + */ +#ifdef CONFIG_THUMB2_KERNEL +#define BUG_INSTR_VALUE 0xde02 +#define BUG_INSTR_TYPE ".hword " #else +#define BUG_INSTR_VALUE 0xe7f001f2 +#define BUG_INSTR_TYPE ".word " +#endif -/* this just causes an oops */ -#define BUG() do { *(int *)0 = 0; } while (1) -#endif +#define BUG() _BUG(__FILE__, __LINE__, BUG_INSTR_VALUE) +#define _BUG(file, line, value) __BUG(file, line, value) + +#ifdef CONFIG_DEBUG_BUGVERBOSE + +/* + * The extra indirection is to ensure that the __FILE__ string comes through + * OK. Many version of gcc do not support the asm %c parameter which would be + * preferable to this unpleasantness. We use mergeable string sections to + * avoid multiple copies of the string appearing in the kernel image. + */ + +#define __BUG(__file, __line, __value) \ +do { \ + BUILD_BUG_ON(sizeof(struct bug_entry) != 12); \ + asm volatile("1:\t" BUG_INSTR_TYPE #__value "\n" \ + ".pushsection .rodata.str, \"aMS\", %progbits, 1\n" \ + "2:\t.asciz " #__file "\n" \ + ".popsection\n" \ + ".pushsection __bug_table,\"a\"\n" \ + "3:\t.word 1b, 2b\n" \ + "\t.hword " #__line ", 0\n" \ + ".popsection"); \ + unreachable(); \ +} while (0) + +#else /* not CONFIG_DEBUG_BUGVERBOSE */ + +#define __BUG(__file, __line, __value) \ +do { \ + asm volatile(BUG_INSTR_TYPE #__value); \ + unreachable(); \ +} while (0) +#endif /* CONFIG_DEBUG_BUGVERBOSE */ #define HAVE_ARCH_BUG -#endif +#endif /* CONFIG_BUG */ #include diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index bc9f9da782cb85ff3eb0171b9c0d5b8630397c90..74969248c375ee3d5c60f0a98f2d5018252fa50f 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -270,6 +271,8 @@ void die(const char *str, struct pt_regs *regs, int err) spin_lock_irq(&die_lock); console_verbose(); bust_spinlocks(1); + if (!user_mode(regs)) + report_bug(regs->ARM_pc, regs); ret = __die(str, err, thread, regs); if (regs && kexec_should_crash(thread->task)) @@ -301,6 +304,24 @@ void arm_notify_die(const char *str, struct pt_regs *regs, } } +#ifdef CONFIG_GENERIC_BUG + +int is_valid_bugaddr(unsigned long pc) +{ +#ifdef CONFIG_THUMB2_KERNEL + unsigned short bkpt; +#else + unsigned long bkpt; +#endif + + if (probe_kernel_address((unsigned *)pc, bkpt)) + return 0; + + return bkpt == BUG_INSTR_VALUE; +} + +#endif + static LIST_HEAD(undef_hook); static DEFINE_SPINLOCK(undef_lock); @@ -706,16 +727,6 @@ baddataabort(int code, unsigned long instr, struct pt_regs *regs) arm_notify_die("unknown data abort code", regs, &info, instr, 0); } -void __attribute__((noreturn)) __bug(const char *file, int line) -{ - printk(KERN_CRIT"kernel BUG at %s:%d!\n", file, line); - *(int *)0 = 0; - - /* Avoid "noreturn function does return" */ - for (;;); -} -EXPORT_SYMBOL(__bug); - void __readwrite_bug(const char *fn) { 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 bf977f8514f60191e478e8e25a696c93d2802b87..7b2541efd9f8cc1980fc57422eb7d19b2a15f716 100644 --- a/arch/arm/kernel/vmlinux.lds.S +++ b/arch/arm/kernel/vmlinux.lds.S @@ -21,7 +21,8 @@ #define ARM_CPU_KEEP(x) #endif -#if defined(CONFIG_SMP_ON_UP) && !defined(CONFIG_DEBUG_SPINLOCK) +#if (defined(CONFIG_SMP_ON_UP) && !defined(CONFIG_DEBUG_SPINLOCK)) || \ + defined(CONFIG_GENERIC_BUG) #define ARM_EXIT_KEEP(x) x #else #define ARM_EXIT_KEEP(x)