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