From: Jeremy Fitzhardinge This makes i386 use the generic BUG machinery. There are no functional changes from the old i386 implementation. The main advantage in using the generic BUG machinery for i386 is that the inlined overhead of BUG is just the ud2a instruction; the file+line(+function) information are no longer inlined into the instruction stream. This reduces cache pollution, and makes disassembly work properly. Signed-off-by: Jeremy Fitzhardinge Cc: Andi Kleen Cc: Hugh Dickens Cc: Michael Ellerman Cc: Paul Mackerras Cc: Benjamin Herrenschmidt Cc: Rusty Russell Signed-off-by: Andrew Morton --- arch/i386/Kconfig | 5 +++ arch/i386/kernel/module.c | 5 +++ arch/i386/kernel/traps.c | 41 ++++++++----------------------- arch/i386/kernel/vmlinux.lds.S | 2 + include/asm-i386/bug.h | 28 +++++++++++++++------ lib/Kconfig.debug | 2 - 6 files changed, 43 insertions(+), 40 deletions(-) diff -puN arch/i386/Kconfig~generic-bug-for-i386 arch/i386/Kconfig --- a/arch/i386/Kconfig~generic-bug-for-i386 +++ a/arch/i386/Kconfig @@ -53,6 +53,11 @@ config GENERIC_IOMAP bool default y +config GENERIC_BUG + bool + default y + depends on BUG + config GENERIC_HWEIGHT bool default y diff -puN arch/i386/kernel/module.c~generic-bug-for-i386 arch/i386/kernel/module.c --- a/arch/i386/kernel/module.c~generic-bug-for-i386 +++ a/arch/i386/kernel/module.c @@ -21,6 +21,7 @@ #include #include #include +#include #if 0 #define DEBUGP printk @@ -132,10 +133,12 @@ int module_finalize(const Elf_Ehdr *hdr, lseg, lseg + locks->sh_size, tseg, tseg + text->sh_size); } - return 0; + + return module_bug_finalize(hdr, sechdrs, me); } void module_arch_cleanup(struct module *mod) { alternatives_smp_module_del(mod); + module_bug_cleanup(mod); } diff -puN arch/i386/kernel/traps.c~generic-bug-for-i386 arch/i386/kernel/traps.c --- a/arch/i386/kernel/traps.c~generic-bug-for-i386 +++ a/arch/i386/kernel/traps.c @@ -29,6 +29,7 @@ #include #include #include +#include #ifdef CONFIG_EISA #include @@ -409,43 +410,22 @@ void show_registers(struct pt_regs *regs printk("\n"); } -static void handle_BUG(struct pt_regs *regs) +int is_valid_bugaddr(unsigned long eip) { - unsigned long eip = regs->eip; unsigned short ud2; if (eip < PAGE_OFFSET) - return; + return 0; if (probe_kernel_address((unsigned short __user *)eip, ud2)) - return; - if (ud2 != 0x0b0f) - return; - - printk(KERN_EMERG "------------[ cut here ]------------\n"); - -#ifdef CONFIG_DEBUG_BUGVERBOSE - do { - unsigned short line; - char *file; - char c; - - if (probe_kernel_address((unsigned short __user *)(eip + 2), - line)) - break; - if (__get_user(file, (char * __user *)(eip + 4)) || - (unsigned long)file < PAGE_OFFSET || __get_user(c, file)) - file = ""; + return 0; - printk(KERN_EMERG "kernel BUG at %s:%d!\n", file, line); - return; - } while (0); -#endif - printk(KERN_EMERG "Kernel BUG at [verbose debug info unavailable]\n"); + return ud2 == 0x0b0f; } -/* This is gone through when something in the kernel - * has done something bad and is about to be terminated. -*/ +/* + * This is gone through when something in the kernel has done something bad and + * is about to be terminated. + */ void die(const char * str, struct pt_regs * regs, long err) { static struct { @@ -478,7 +458,8 @@ void die(const char * str, struct pt_reg unsigned long esp; unsigned short ss; - handle_BUG(regs); + report_bug(regs->eip); + printk(KERN_EMERG "%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter); #ifdef CONFIG_PREEMPT printk(KERN_EMERG "PREEMPT "); diff -puN arch/i386/kernel/vmlinux.lds.S~generic-bug-for-i386 arch/i386/kernel/vmlinux.lds.S --- a/arch/i386/kernel/vmlinux.lds.S~generic-bug-for-i386 +++ a/arch/i386/kernel/vmlinux.lds.S @@ -45,6 +45,8 @@ SECTIONS RODATA + BUG_TABLE + . = ALIGN(4); __tracedata_start = .; .tracedata : AT(ADDR(.tracedata) - LOAD_OFFSET) { diff -puN include/asm-i386/bug.h~generic-bug-for-i386 include/asm-i386/bug.h --- a/include/asm-i386/bug.h~generic-bug-for-i386 +++ a/include/asm-i386/bug.h @@ -4,20 +4,32 @@ /* * Tell the user there is some problem. - * The offending file and line are encoded after the "officially - * undefined" opcode for parsing in the trap handler. + * The offending file and line are encoded encoded in the __bug_table section. */ #ifdef CONFIG_BUG #define HAVE_ARCH_BUG + #ifdef CONFIG_DEBUG_BUGVERBOSE -#define BUG() \ - __asm__ __volatile__( "ud2\n" \ - "\t.word %c0\n" \ - "\t.long %c1\n" \ - : : "i" (__LINE__), "i" (__FILE__)) +#define BUG() \ + do { \ + asm volatile("1:\tud2\n" \ + ".pushsection __bug_table,\"a\"\n" \ + "2:\t.long 1b, %c0\n" \ + "\t.word %c1, 0\n" \ + "\t.org 2b+%c2\n" \ + ".popsection" \ + : : "i" (__FILE__), "i" (__LINE__), \ + "i" (sizeof(struct bug_entry))); \ + for(;;) ; \ + } while(0) + #else -#define BUG() __asm__ __volatile__("ud2\n") +#define BUG() \ + do { \ + asm volatile("ud2"); \ + for(;;) ; \ + } while(0) #endif #endif diff -puN lib/Kconfig.debug~generic-bug-for-i386 lib/Kconfig.debug --- a/lib/Kconfig.debug~generic-bug-for-i386 +++ a/lib/Kconfig.debug @@ -284,7 +284,7 @@ config DEBUG_HIGHMEM config DEBUG_BUGVERBOSE bool "Verbose BUG() reporting (adds 70K)" if DEBUG_KERNEL && EMBEDDED depends on BUG - depends on ARM || ARM26 || AVR32 || M32R || M68K || SPARC32 || SPARC64 || X86_32 || FRV || SUPERH || GENERIC_BUG + depends on ARM || ARM26 || AVR32 || M32R || M68K || SPARC32 || SPARC64 || FRV || SUPERH || GENERIC_BUG default !EMBEDDED help Say Y here to make BUG() panics output the file name and line number _