Blame view
lib/bug.c
4.55 KB
7664c5a1d [PATCH] Generic B... |
1 2 3 4 5 6 7 |
/* Generic support for BUG() This respects the following config options: CONFIG_BUG - emit BUG traps. Nothing happens without this. CONFIG_GENERIC_BUG - enable this code. |
b93a531e3 allow bug table e... |
8 9 |
CONFIG_GENERIC_BUG_RELATIVE_POINTERS - use 32-bit pointers relative to the containing struct bug_entry for bug_addr and file. |
7664c5a1d [PATCH] Generic B... |
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
CONFIG_DEBUG_BUGVERBOSE - emit full file+line information for each BUG CONFIG_BUG and CONFIG_DEBUG_BUGVERBOSE are potentially user-settable (though they're generally always on). CONFIG_GENERIC_BUG is set by each architecture using this code. To use this, your architecture must: 1. Set up the config options: - Enable CONFIG_GENERIC_BUG if CONFIG_BUG 2. Implement BUG (and optionally BUG_ON, WARN, WARN_ON) - Define HAVE_ARCH_BUG - Implement BUG() to generate a faulting instruction - NOTE: struct bug_entry does not have "file" or "line" entries when CONFIG_DEBUG_BUGVERBOSE is not enabled, so you must generate the values accordingly. 3. Implement the trap - In the illegal instruction trap handler (typically), verify that the fault was in kernel mode, and call report_bug() - report_bug() will return whether it was a false alarm, a warning, or an actual bug. - You must implement the is_valid_bugaddr(bugaddr) callback which returns true if the eip is a real kernel address, and it points to the expected BUG trap instruction. Jeremy Fitzhardinge <jeremy@goop.org> 2006 */ #include <linux/list.h> #include <linux/module.h> |
da9eac899 lib: taint kernel... |
42 |
#include <linux/kernel.h> |
7664c5a1d [PATCH] Generic B... |
43 |
#include <linux/bug.h> |
608e26196 generic bug: use ... |
44 |
#include <linux/sched.h> |
7664c5a1d [PATCH] Generic B... |
45 46 |
extern const struct bug_entry __start___bug_table[], __stop___bug_table[]; |
b93a531e3 allow bug table e... |
47 48 49 50 51 52 53 54 |
static inline unsigned long bug_addr(const struct bug_entry *bug) { #ifndef CONFIG_GENERIC_BUG_RELATIVE_POINTERS return bug->bug_addr; #else return (unsigned long)bug + bug->bug_addr_disp; #endif } |
7664c5a1d [PATCH] Generic B... |
55 56 57 58 59 60 61 62 63 64 65 66 |
#ifdef CONFIG_MODULES static LIST_HEAD(module_bug_list); static const struct bug_entry *module_find_bug(unsigned long bugaddr) { struct module *mod; list_for_each_entry(mod, &module_bug_list, bug_list) { const struct bug_entry *bug = mod->bug_table; unsigned i; for (i = 0; i < mod->num_bugs; ++i, ++bug) |
b93a531e3 allow bug table e... |
67 |
if (bugaddr == bug_addr(bug)) |
7664c5a1d [PATCH] Generic B... |
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 |
return bug; } return NULL; } int module_bug_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs, struct module *mod) { char *secstrings; unsigned int i; mod->bug_table = NULL; mod->num_bugs = 0; /* Find the __bug_table section, if present */ secstrings = (char *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; for (i = 1; i < hdr->e_shnum; i++) { if (strcmp(secstrings+sechdrs[i].sh_name, "__bug_table")) continue; mod->bug_table = (void *) sechdrs[i].sh_addr; mod->num_bugs = sechdrs[i].sh_size / sizeof(struct bug_entry); break; } /* * Strictly speaking this should have a spinlock to protect against * traversals, but since we only traverse on BUG()s, a spinlock * could potentially lead to deadlock and thus be counter-productive. */ list_add(&mod->bug_list, &module_bug_list); return 0; } void module_bug_cleanup(struct module *mod) { list_del(&mod->bug_list); } #else static inline const struct bug_entry *module_find_bug(unsigned long bugaddr) { return NULL; } #endif const struct bug_entry *find_bug(unsigned long bugaddr) { const struct bug_entry *bug; for (bug = __start___bug_table; bug < __stop___bug_table; ++bug) |
b93a531e3 allow bug table e... |
120 |
if (bugaddr == bug_addr(bug)) |
7664c5a1d [PATCH] Generic B... |
121 122 123 124 |
return bug; return module_find_bug(bugaddr); } |
608e26196 generic bug: use ... |
125 |
enum bug_trap_type report_bug(unsigned long bugaddr, struct pt_regs *regs) |
7664c5a1d [PATCH] Generic B... |
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 |
{ const struct bug_entry *bug; const char *file; unsigned line, warning; if (!is_valid_bugaddr(bugaddr)) return BUG_TRAP_TYPE_NONE; bug = find_bug(bugaddr); printk(KERN_EMERG "------------[ cut here ]------------ "); file = NULL; line = 0; warning = 0; if (bug) { #ifdef CONFIG_DEBUG_BUGVERBOSE |
b93a531e3 allow bug table e... |
145 |
#ifndef CONFIG_GENERIC_BUG_RELATIVE_POINTERS |
7664c5a1d [PATCH] Generic B... |
146 |
file = bug->file; |
b93a531e3 allow bug table e... |
147 148 149 |
#else file = (const char *)bug + bug->file_disp; #endif |
7664c5a1d [PATCH] Generic B... |
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 |
line = bug->line; #endif warning = (bug->flags & BUGFLAG_WARNING) != 0; } if (warning) { /* this is a WARN_ON rather than BUG/BUG_ON */ if (file) printk(KERN_ERR "Badness at %s:%u ", file, line); else printk(KERN_ERR "Badness at %p " "[verbose debug info unavailable] ", (void *)bugaddr); |
608e26196 generic bug: use ... |
166 |
show_regs(regs); |
da9eac899 lib: taint kernel... |
167 |
add_taint(TAINT_WARN); |
7664c5a1d [PATCH] Generic B... |
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 |
return BUG_TRAP_TYPE_WARN; } if (file) printk(KERN_CRIT "kernel BUG at %s:%u! ", file, line); else printk(KERN_CRIT "Kernel BUG at %p " "[verbose debug info unavailable] ", (void *)bugaddr); return BUG_TRAP_TYPE_BUG; } |