Blame view

lib/bug.c 5.89 KB
b24413180   Greg Kroah-Hartman   License cleanup: ...
1
  // SPDX-License-Identifier: GPL-2.0
7664c5a1d   Jeremy Fitzhardinge   [PATCH] Generic B...
2
3
4
5
6
7
8
  /*
    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   Jan Beulich   allow bug table e...
9
10
    CONFIG_GENERIC_BUG_RELATIVE_POINTERS - use 32-bit pointers relative to
  	the containing struct bug_entry for bug_addr and file.
7664c5a1d   Jeremy Fitzhardinge   [PATCH] Generic B...
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
    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
   */
c56ba7033   Fabian Frederick   lib/bug.c: conver...
41
42
  
  #define pr_fmt(fmt) fmt
7664c5a1d   Jeremy Fitzhardinge   [PATCH] Generic B...
43
44
  #include <linux/list.h>
  #include <linux/module.h>
da9eac899   Paul Mundt   lib: taint kernel...
45
  #include <linux/kernel.h>
7664c5a1d   Jeremy Fitzhardinge   [PATCH] Generic B...
46
  #include <linux/bug.h>
608e26196   Heiko Carstens   generic bug: use ...
47
  #include <linux/sched.h>
b2d091031   Ingo Molnar   sched/headers: Pr...
48
  #include <linux/rculist.h>
58f6e3844   Peter Zijlstra   ftrace,bug: Impro...
49
  #include <linux/ftrace.h>
7664c5a1d   Jeremy Fitzhardinge   [PATCH] Generic B...
50

19d436268   Peter Zijlstra   debug: Add _ONCE(...
51
  extern struct bug_entry __start___bug_table[], __stop___bug_table[];
7664c5a1d   Jeremy Fitzhardinge   [PATCH] Generic B...
52

b93a531e3   Jan Beulich   allow bug table e...
53
54
55
56
57
58
59
60
  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   Jeremy Fitzhardinge   [PATCH] Generic B...
61
  #ifdef CONFIG_MODULES
1fb9341ac   Rusty Russell   module: put modul...
62
  /* Updates are protected by module mutex */
7664c5a1d   Jeremy Fitzhardinge   [PATCH] Generic B...
63
  static LIST_HEAD(module_bug_list);
19d436268   Peter Zijlstra   debug: Add _ONCE(...
64
  static struct bug_entry *module_find_bug(unsigned long bugaddr)
7664c5a1d   Jeremy Fitzhardinge   [PATCH] Generic B...
65
66
  {
  	struct module *mod;
19d436268   Peter Zijlstra   debug: Add _ONCE(...
67
  	struct bug_entry *bug = NULL;
7664c5a1d   Jeremy Fitzhardinge   [PATCH] Generic B...
68

0be964be0   Peter Zijlstra   module: Sanitize ...
69
  	rcu_read_lock_sched();
0286b5ea1   Masami Hiramatsu   lib/bug: Use RCU ...
70
  	list_for_each_entry_rcu(mod, &module_bug_list, bug_list) {
7664c5a1d   Jeremy Fitzhardinge   [PATCH] Generic B...
71
  		unsigned i;
0286b5ea1   Masami Hiramatsu   lib/bug: Use RCU ...
72
  		bug = mod->bug_table;
7664c5a1d   Jeremy Fitzhardinge   [PATCH] Generic B...
73
  		for (i = 0; i < mod->num_bugs; ++i, ++bug)
b93a531e3   Jan Beulich   allow bug table e...
74
  			if (bugaddr == bug_addr(bug))
0286b5ea1   Masami Hiramatsu   lib/bug: Use RCU ...
75
  				goto out;
7664c5a1d   Jeremy Fitzhardinge   [PATCH] Generic B...
76
  	}
0286b5ea1   Masami Hiramatsu   lib/bug: Use RCU ...
77
78
  	bug = NULL;
  out:
0be964be0   Peter Zijlstra   module: Sanitize ...
79
  	rcu_read_unlock_sched();
0286b5ea1   Masami Hiramatsu   lib/bug: Use RCU ...
80
81
  
  	return bug;
7664c5a1d   Jeremy Fitzhardinge   [PATCH] Generic B...
82
  }
5336377d6   Linus Torvalds   modules: Fix modu...
83
84
  void module_bug_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs,
  			 struct module *mod)
7664c5a1d   Jeremy Fitzhardinge   [PATCH] Generic B...
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
  {
  	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.
0286b5ea1   Masami Hiramatsu   lib/bug: Use RCU ...
106
107
  	 * Thus, this uses RCU to safely manipulate the bug list, since BUG
  	 * must run in non-interruptive state.
7664c5a1d   Jeremy Fitzhardinge   [PATCH] Generic B...
108
  	 */
0286b5ea1   Masami Hiramatsu   lib/bug: Use RCU ...
109
  	list_add_rcu(&mod->bug_list, &module_bug_list);
7664c5a1d   Jeremy Fitzhardinge   [PATCH] Generic B...
110
111
112
113
  }
  
  void module_bug_cleanup(struct module *mod)
  {
0286b5ea1   Masami Hiramatsu   lib/bug: Use RCU ...
114
  	list_del_rcu(&mod->bug_list);
7664c5a1d   Jeremy Fitzhardinge   [PATCH] Generic B...
115
116
117
  }
  
  #else
19d436268   Peter Zijlstra   debug: Add _ONCE(...
118
  static inline struct bug_entry *module_find_bug(unsigned long bugaddr)
7664c5a1d   Jeremy Fitzhardinge   [PATCH] Generic B...
119
120
121
122
  {
  	return NULL;
  }
  #endif
26dbc7e29   Andrew Scull   bug: Factor out a...
123
124
125
  void bug_get_file_line(struct bug_entry *bug, const char **file,
  		       unsigned int *line)
  {
26dbc7e29   Andrew Scull   bug: Factor out a...
126
127
128
129
130
131
132
  #ifdef CONFIG_DEBUG_BUGVERBOSE
  #ifndef CONFIG_GENERIC_BUG_RELATIVE_POINTERS
  	*file = bug->file;
  #else
  	*file = (const char *)bug + bug->file_disp;
  #endif
  	*line = bug->line;
5b8be5d87   Andrew Scull   bug: Assign value...
133
134
135
  #else
  	*file = NULL;
  	*line = 0;
26dbc7e29   Andrew Scull   bug: Factor out a...
136
137
  #endif
  }
19d436268   Peter Zijlstra   debug: Add _ONCE(...
138
  struct bug_entry *find_bug(unsigned long bugaddr)
7664c5a1d   Jeremy Fitzhardinge   [PATCH] Generic B...
139
  {
19d436268   Peter Zijlstra   debug: Add _ONCE(...
140
  	struct bug_entry *bug;
7664c5a1d   Jeremy Fitzhardinge   [PATCH] Generic B...
141
142
  
  	for (bug = __start___bug_table; bug < __stop___bug_table; ++bug)
b93a531e3   Jan Beulich   allow bug table e...
143
  		if (bugaddr == bug_addr(bug))
7664c5a1d   Jeremy Fitzhardinge   [PATCH] Generic B...
144
145
146
147
  			return bug;
  
  	return module_find_bug(bugaddr);
  }
608e26196   Heiko Carstens   generic bug: use ...
148
  enum bug_trap_type report_bug(unsigned long bugaddr, struct pt_regs *regs)
7664c5a1d   Jeremy Fitzhardinge   [PATCH] Generic B...
149
  {
19d436268   Peter Zijlstra   debug: Add _ONCE(...
150
  	struct bug_entry *bug;
7664c5a1d   Jeremy Fitzhardinge   [PATCH] Generic B...
151
  	const char *file;
19d436268   Peter Zijlstra   debug: Add _ONCE(...
152
  	unsigned line, warning, once, done;
7664c5a1d   Jeremy Fitzhardinge   [PATCH] Generic B...
153
154
155
156
157
  
  	if (!is_valid_bugaddr(bugaddr))
  		return BUG_TRAP_TYPE_NONE;
  
  	bug = find_bug(bugaddr);
1b4cfe3c0   Kees Cook   lib/bug.c: exclud...
158
159
  	if (!bug)
  		return BUG_TRAP_TYPE_NONE;
7664c5a1d   Jeremy Fitzhardinge   [PATCH] Generic B...
160

58f6e3844   Peter Zijlstra   ftrace,bug: Impro...
161
  	disable_trace_on_warning();
26dbc7e29   Andrew Scull   bug: Factor out a...
162
  	bug_get_file_line(bug, &file, &line);
7664c5a1d   Jeremy Fitzhardinge   [PATCH] Generic B...
163

3ad1a6cb0   Andrew Scull   bug: Remove redun...
164
165
166
167
168
169
170
171
172
173
174
175
  	warning = (bug->flags & BUGFLAG_WARNING) != 0;
  	once = (bug->flags & BUGFLAG_ONCE) != 0;
  	done = (bug->flags & BUGFLAG_DONE) != 0;
  
  	if (warning && once) {
  		if (done)
  			return BUG_TRAP_TYPE_WARN;
  
  		/*
  		 * Since this is the only store, concurrency is not an issue.
  		 */
  		bug->flags |= BUGFLAG_DONE;
7664c5a1d   Jeremy Fitzhardinge   [PATCH] Generic B...
176
  	}
a44f71a9a   Kees Cook   bug: move WARN_ON...
177
178
179
180
181
182
183
184
  	/*
  	 * BUG() and WARN_ON() families don't print a custom debug message
  	 * before triggering the exception handler, so we must add the
  	 * "cut here" line now. WARN() issues its own "cut here" before the
  	 * extra debugging message it writes before triggering the handler.
  	 */
  	if ((bug->flags & BUGFLAG_NO_CUT_HERE) == 0)
  		printk(KERN_DEFAULT CUT_HERE);
7664c5a1d   Jeremy Fitzhardinge   [PATCH] Generic B...
185
186
  	if (warning) {
  		/* this is a WARN_ON rather than BUG/BUG_ON */
2553b67a1   Josh Poimboeuf   lib/bug.c: use co...
187
188
  		__warn(file, line, (void *)bugaddr, BUG_GET_TAINT(bug), regs,
  		       NULL);
7664c5a1d   Jeremy Fitzhardinge   [PATCH] Generic B...
189
190
191
192
  		return BUG_TRAP_TYPE_WARN;
  	}
  
  	if (file)
c56ba7033   Fabian Frederick   lib/bug.c: conver...
193
194
  		pr_crit("kernel BUG at %s:%u!
  ", file, line);
7664c5a1d   Jeremy Fitzhardinge   [PATCH] Generic B...
195
  	else
0862ca422   Kees Cook   bug: use %pB in B...
196
197
  		pr_crit("Kernel BUG at %pB [verbose debug info unavailable]
  ",
c56ba7033   Fabian Frederick   lib/bug.c: conver...
198
  			(void *)bugaddr);
7664c5a1d   Jeremy Fitzhardinge   [PATCH] Generic B...
199
200
201
  
  	return BUG_TRAP_TYPE_BUG;
  }
aaf5dcfb2   Andi Kleen   kernel debug: sup...
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
  
  static void clear_once_table(struct bug_entry *start, struct bug_entry *end)
  {
  	struct bug_entry *bug;
  
  	for (bug = start; bug < end; bug++)
  		bug->flags &= ~BUGFLAG_DONE;
  }
  
  void generic_bug_clear_once(void)
  {
  #ifdef CONFIG_MODULES
  	struct module *mod;
  
  	rcu_read_lock_sched();
  	list_for_each_entry_rcu(mod, &module_bug_list, bug_list)
  		clear_once_table(mod->bug_table,
  				 mod->bug_table + mod->num_bugs);
  	rcu_read_unlock_sched();
  #endif
  
  	clear_once_table(__start___bug_table, __stop___bug_table);
  }