Blame view

lib/bug.c 4.08 KB
7664c5a1d   Jeremy Fitzhardinge   [PATCH] Generic B...
1
2
3
4
5
6
7
8
9
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
  /*
    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.
    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>
  #include <linux/bug.h>
608e26196   Heiko Carstens   generic bug: use ...
41
  #include <linux/sched.h>
7664c5a1d   Jeremy Fitzhardinge   [PATCH] Generic B...
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
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
  
  extern const struct bug_entry __start___bug_table[], __stop___bug_table[];
  
  #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)
  			if (bugaddr == bug->bug_addr)
  				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)
  		if (bugaddr == bug->bug_addr)
  			return bug;
  
  	return module_find_bug(bugaddr);
  }
608e26196   Heiko Carstens   generic bug: use ...
115
  enum bug_trap_type report_bug(unsigned long bugaddr, struct pt_regs *regs)
7664c5a1d   Jeremy Fitzhardinge   [PATCH] Generic B...
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
  {
  	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
  		file = bug->file;
  		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   Heiko Carstens   generic bug: use ...
152
  		show_regs(regs);
7664c5a1d   Jeremy Fitzhardinge   [PATCH] Generic B...
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
  		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;
  }