Blame view

lib/bug.c 4.69 KB
7664c5a1d   Jeremy Fitzhardinge   [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   Jan Beulich   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   Jeremy Fitzhardinge   [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
    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...
40
41
  
  #define pr_fmt(fmt) fmt
7664c5a1d   Jeremy Fitzhardinge   [PATCH] Generic B...
42
43
  #include <linux/list.h>
  #include <linux/module.h>
da9eac899   Paul Mundt   lib: taint kernel...
44
  #include <linux/kernel.h>
7664c5a1d   Jeremy Fitzhardinge   [PATCH] Generic B...
45
  #include <linux/bug.h>
608e26196   Heiko Carstens   generic bug: use ...
46
  #include <linux/sched.h>
7664c5a1d   Jeremy Fitzhardinge   [PATCH] Generic B...
47
48
  
  extern const struct bug_entry __start___bug_table[], __stop___bug_table[];
b93a531e3   Jan Beulich   allow bug table e...
49
50
51
52
53
54
55
56
  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...
57
  #ifdef CONFIG_MODULES
1fb9341ac   Rusty Russell   module: put modul...
58
  /* Updates are protected by module mutex */
7664c5a1d   Jeremy Fitzhardinge   [PATCH] Generic B...
59
60
61
62
63
64
65
66
67
68
69
  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   Jan Beulich   allow bug table e...
70
  			if (bugaddr == bug_addr(bug))
7664c5a1d   Jeremy Fitzhardinge   [PATCH] Generic B...
71
72
73
74
  				return bug;
  	}
  	return NULL;
  }
5336377d6   Linus Torvalds   modules: Fix modu...
75
76
  void module_bug_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs,
  			 struct module *mod)
7664c5a1d   Jeremy Fitzhardinge   [PATCH] Generic B...
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
  {
  	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);
7664c5a1d   Jeremy Fitzhardinge   [PATCH] Generic B...
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
  }
  
  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   Jan Beulich   allow bug table e...
120
  		if (bugaddr == bug_addr(bug))
7664c5a1d   Jeremy Fitzhardinge   [PATCH] Generic B...
121
122
123
124
  			return bug;
  
  	return module_find_bug(bugaddr);
  }
608e26196   Heiko Carstens   generic bug: use ...
125
  enum bug_trap_type report_bug(unsigned long bugaddr, struct pt_regs *regs)
7664c5a1d   Jeremy Fitzhardinge   [PATCH] Generic B...
126
127
128
129
130
131
132
133
134
  {
  	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);
7664c5a1d   Jeremy Fitzhardinge   [PATCH] Generic B...
135
136
137
138
139
140
  	file = NULL;
  	line = 0;
  	warning = 0;
  
  	if (bug) {
  #ifdef CONFIG_DEBUG_BUGVERBOSE
b93a531e3   Jan Beulich   allow bug table e...
141
  #ifndef CONFIG_GENERIC_BUG_RELATIVE_POINTERS
7664c5a1d   Jeremy Fitzhardinge   [PATCH] Generic B...
142
  		file = bug->file;
b93a531e3   Jan Beulich   allow bug table e...
143
144
145
  #else
  		file = (const char *)bug + bug->file_disp;
  #endif
7664c5a1d   Jeremy Fitzhardinge   [PATCH] Generic B...
146
147
148
149
150
151
152
  		line = bug->line;
  #endif
  		warning = (bug->flags & BUGFLAG_WARNING) != 0;
  	}
  
  	if (warning) {
  		/* this is a WARN_ON rather than BUG/BUG_ON */
c56ba7033   Fabian Frederick   lib/bug.c: conver...
153
154
  		pr_warn("------------[ cut here ]------------
  ");
e2e7e0932   Anton Blanchard   lib/bug.c: make W...
155

7664c5a1d   Jeremy Fitzhardinge   [PATCH] Generic B...
156
  		if (file)
c56ba7033   Fabian Frederick   lib/bug.c: conver...
157
158
  			pr_warn("WARNING: at %s:%u
  ", file, line);
7664c5a1d   Jeremy Fitzhardinge   [PATCH] Generic B...
159
  		else
c56ba7033   Fabian Frederick   lib/bug.c: conver...
160
161
162
  			pr_warn("WARNING: at %p [verbose debug info unavailable]
  ",
  				(void *)bugaddr);
7664c5a1d   Jeremy Fitzhardinge   [PATCH] Generic B...
163

e2e7e0932   Anton Blanchard   lib/bug.c: make W...
164
  		print_modules();
608e26196   Heiko Carstens   generic bug: use ...
165
  		show_regs(regs);
863a60492   Anton Blanchard   lib/bug.c: add oo...
166
  		print_oops_end_marker();
373d4d099   Rusty Russell   taint: add explic...
167
168
  		/* Just a warning, don't kill lockdep. */
  		add_taint(BUG_GET_TAINT(bug), LOCKDEP_STILL_OK);
7664c5a1d   Jeremy Fitzhardinge   [PATCH] Generic B...
169
170
  		return BUG_TRAP_TYPE_WARN;
  	}
b0f4c4b32   Prarit Bhargava   bugs, x86: Fix pr...
171
172
  	printk(KERN_DEFAULT "------------[ cut here ]------------
  ");
e2e7e0932   Anton Blanchard   lib/bug.c: make W...
173

7664c5a1d   Jeremy Fitzhardinge   [PATCH] Generic B...
174
  	if (file)
c56ba7033   Fabian Frederick   lib/bug.c: conver...
175
176
  		pr_crit("kernel BUG at %s:%u!
  ", file, line);
7664c5a1d   Jeremy Fitzhardinge   [PATCH] Generic B...
177
  	else
c56ba7033   Fabian Frederick   lib/bug.c: conver...
178
179
180
  		pr_crit("Kernel BUG at %p [verbose debug info unavailable]
  ",
  			(void *)bugaddr);
7664c5a1d   Jeremy Fitzhardinge   [PATCH] Generic B...
181
182
183
  
  	return BUG_TRAP_TYPE_BUG;
  }