-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
yaml --- r: 43507 b: refs/heads/master c: 7664c5a h: refs/heads/master i: 43505: f42df48 43503: 103c8f0 v: v3
- Loading branch information
Jeremy Fitzhardinge
authored and
Linus Torvalds
committed
Dec 8, 2006
1 parent
96f6470
commit 5250c60
Showing
8 changed files
with
245 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
--- | ||
refs/heads/master: c48f70c3d046f021b1c22438604ef2a583380eca | ||
refs/heads/master: 7664c5a1da4711bb6383117f51b94c8dc8f3f1cd |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
#ifndef _LINUX_BUG_H | ||
#define _LINUX_BUG_H | ||
|
||
#include <linux/module.h> | ||
#include <asm/bug.h> | ||
|
||
enum bug_trap_type { | ||
BUG_TRAP_TYPE_NONE = 0, | ||
BUG_TRAP_TYPE_WARN = 1, | ||
BUG_TRAP_TYPE_BUG = 2, | ||
}; | ||
|
||
#ifdef CONFIG_GENERIC_BUG | ||
#include <asm-generic/bug.h> | ||
|
||
static inline int is_warning_bug(const struct bug_entry *bug) | ||
{ | ||
return bug->flags & BUGFLAG_WARNING; | ||
} | ||
|
||
const struct bug_entry *find_bug(unsigned long bugaddr); | ||
|
||
enum bug_trap_type report_bug(unsigned long bug_addr); | ||
|
||
int module_bug_finalize(const Elf_Ehdr *, const Elf_Shdr *, | ||
struct module *); | ||
void module_bug_cleanup(struct module *); | ||
|
||
/* These are defined by the architecture */ | ||
int is_valid_bugaddr(unsigned long addr); | ||
|
||
#else /* !CONFIG_GENERIC_BUG */ | ||
|
||
static inline enum bug_trap_type report_bug(unsigned long bug_addr) | ||
{ | ||
return BUG_TRAP_TYPE_BUG; | ||
} | ||
static inline int module_bug_finalize(const Elf_Ehdr *hdr, | ||
const Elf_Shdr *sechdrs, | ||
struct module *mod) | ||
{ | ||
return 0; | ||
} | ||
static inline void module_bug_cleanup(struct module *mod) {} | ||
|
||
#endif /* CONFIG_GENERIC_BUG */ | ||
#endif /* _LINUX_BUG_H */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,163 @@ | ||
/* | ||
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> | ||
|
||
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); | ||
} | ||
|
||
enum bug_trap_type report_bug(unsigned long bugaddr) | ||
{ | ||
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 ]------------\n"); | ||
|
||
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\n", | ||
file, line); | ||
else | ||
printk(KERN_ERR "Badness at %p " | ||
"[verbose debug info unavailable]\n", | ||
(void *)bugaddr); | ||
|
||
dump_stack(); | ||
return BUG_TRAP_TYPE_WARN; | ||
} | ||
|
||
if (file) | ||
printk(KERN_CRIT "kernel BUG at %s:%u!\n", | ||
file, line); | ||
else | ||
printk(KERN_CRIT "Kernel BUG at %p " | ||
"[verbose debug info unavailable]\n", | ||
(void *)bugaddr); | ||
|
||
return BUG_TRAP_TYPE_BUG; | ||
} |