Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003   Generic support for BUG()
0004 
0005   This respects the following config options:
0006 
0007   CONFIG_BUG - emit BUG traps.  Nothing happens without this.
0008   CONFIG_GENERIC_BUG - enable this code.
0009   CONFIG_GENERIC_BUG_RELATIVE_POINTERS - use 32-bit relative pointers for bug_addr and file
0010   CONFIG_DEBUG_BUGVERBOSE - emit full file+line information for each BUG
0011 
0012   CONFIG_BUG and CONFIG_DEBUG_BUGVERBOSE are potentially user-settable
0013   (though they're generally always on).
0014 
0015   CONFIG_GENERIC_BUG is set by each architecture using this code.
0016 
0017   To use this, your architecture must:
0018 
0019   1. Set up the config options:
0020      - Enable CONFIG_GENERIC_BUG if CONFIG_BUG
0021 
0022   2. Implement BUG (and optionally BUG_ON, WARN, WARN_ON)
0023      - Define HAVE_ARCH_BUG
0024      - Implement BUG() to generate a faulting instruction
0025      - NOTE: struct bug_entry does not have "file" or "line" entries
0026        when CONFIG_DEBUG_BUGVERBOSE is not enabled, so you must generate
0027        the values accordingly.
0028 
0029   3. Implement the trap
0030      - In the illegal instruction trap handler (typically), verify
0031        that the fault was in kernel mode, and call report_bug()
0032      - report_bug() will return whether it was a false alarm, a warning,
0033        or an actual bug.
0034      - You must implement the is_valid_bugaddr(bugaddr) callback which
0035        returns true if the eip is a real kernel address, and it points
0036        to the expected BUG trap instruction.
0037 
0038     Jeremy Fitzhardinge <jeremy@goop.org> 2006
0039  */
0040 
0041 #define pr_fmt(fmt) fmt
0042 
0043 #include <linux/list.h>
0044 #include <linux/module.h>
0045 #include <linux/kernel.h>
0046 #include <linux/bug.h>
0047 #include <linux/sched.h>
0048 #include <linux/rculist.h>
0049 #include <linux/ftrace.h>
0050 
0051 extern struct bug_entry __start___bug_table[], __stop___bug_table[];
0052 
0053 static inline unsigned long bug_addr(const struct bug_entry *bug)
0054 {
0055 #ifdef CONFIG_GENERIC_BUG_RELATIVE_POINTERS
0056     return (unsigned long)&bug->bug_addr_disp + bug->bug_addr_disp;
0057 #else
0058     return bug->bug_addr;
0059 #endif
0060 }
0061 
0062 #ifdef CONFIG_MODULES
0063 /* Updates are protected by module mutex */
0064 static LIST_HEAD(module_bug_list);
0065 
0066 static struct bug_entry *module_find_bug(unsigned long bugaddr)
0067 {
0068     struct module *mod;
0069     struct bug_entry *bug = NULL;
0070 
0071     rcu_read_lock_sched();
0072     list_for_each_entry_rcu(mod, &module_bug_list, bug_list) {
0073         unsigned i;
0074 
0075         bug = mod->bug_table;
0076         for (i = 0; i < mod->num_bugs; ++i, ++bug)
0077             if (bugaddr == bug_addr(bug))
0078                 goto out;
0079     }
0080     bug = NULL;
0081 out:
0082     rcu_read_unlock_sched();
0083 
0084     return bug;
0085 }
0086 
0087 void module_bug_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs,
0088              struct module *mod)
0089 {
0090     char *secstrings;
0091     unsigned int i;
0092 
0093     mod->bug_table = NULL;
0094     mod->num_bugs = 0;
0095 
0096     /* Find the __bug_table section, if present */
0097     secstrings = (char *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
0098     for (i = 1; i < hdr->e_shnum; i++) {
0099         if (strcmp(secstrings+sechdrs[i].sh_name, "__bug_table"))
0100             continue;
0101         mod->bug_table = (void *) sechdrs[i].sh_addr;
0102         mod->num_bugs = sechdrs[i].sh_size / sizeof(struct bug_entry);
0103         break;
0104     }
0105 
0106     /*
0107      * Strictly speaking this should have a spinlock to protect against
0108      * traversals, but since we only traverse on BUG()s, a spinlock
0109      * could potentially lead to deadlock and thus be counter-productive.
0110      * Thus, this uses RCU to safely manipulate the bug list, since BUG
0111      * must run in non-interruptive state.
0112      */
0113     list_add_rcu(&mod->bug_list, &module_bug_list);
0114 }
0115 
0116 void module_bug_cleanup(struct module *mod)
0117 {
0118     list_del_rcu(&mod->bug_list);
0119 }
0120 
0121 #else
0122 
0123 static inline struct bug_entry *module_find_bug(unsigned long bugaddr)
0124 {
0125     return NULL;
0126 }
0127 #endif
0128 
0129 void bug_get_file_line(struct bug_entry *bug, const char **file,
0130                unsigned int *line)
0131 {
0132 #ifdef CONFIG_DEBUG_BUGVERBOSE
0133 #ifdef CONFIG_GENERIC_BUG_RELATIVE_POINTERS
0134     *file = (const char *)&bug->file_disp + bug->file_disp;
0135 #else
0136     *file = bug->file;
0137 #endif
0138     *line = bug->line;
0139 #else
0140     *file = NULL;
0141     *line = 0;
0142 #endif
0143 }
0144 
0145 struct bug_entry *find_bug(unsigned long bugaddr)
0146 {
0147     struct bug_entry *bug;
0148 
0149     for (bug = __start___bug_table; bug < __stop___bug_table; ++bug)
0150         if (bugaddr == bug_addr(bug))
0151             return bug;
0152 
0153     return module_find_bug(bugaddr);
0154 }
0155 
0156 enum bug_trap_type report_bug(unsigned long bugaddr, struct pt_regs *regs)
0157 {
0158     struct bug_entry *bug;
0159     const char *file;
0160     unsigned line, warning, once, done;
0161 
0162     if (!is_valid_bugaddr(bugaddr))
0163         return BUG_TRAP_TYPE_NONE;
0164 
0165     bug = find_bug(bugaddr);
0166     if (!bug)
0167         return BUG_TRAP_TYPE_NONE;
0168 
0169     disable_trace_on_warning();
0170 
0171     bug_get_file_line(bug, &file, &line);
0172 
0173     warning = (bug->flags & BUGFLAG_WARNING) != 0;
0174     once = (bug->flags & BUGFLAG_ONCE) != 0;
0175     done = (bug->flags & BUGFLAG_DONE) != 0;
0176 
0177     if (warning && once) {
0178         if (done)
0179             return BUG_TRAP_TYPE_WARN;
0180 
0181         /*
0182          * Since this is the only store, concurrency is not an issue.
0183          */
0184         bug->flags |= BUGFLAG_DONE;
0185     }
0186 
0187     /*
0188      * BUG() and WARN_ON() families don't print a custom debug message
0189      * before triggering the exception handler, so we must add the
0190      * "cut here" line now. WARN() issues its own "cut here" before the
0191      * extra debugging message it writes before triggering the handler.
0192      */
0193     if ((bug->flags & BUGFLAG_NO_CUT_HERE) == 0)
0194         printk(KERN_DEFAULT CUT_HERE);
0195 
0196     if (warning) {
0197         /* this is a WARN_ON rather than BUG/BUG_ON */
0198         __warn(file, line, (void *)bugaddr, BUG_GET_TAINT(bug), regs,
0199                NULL);
0200         return BUG_TRAP_TYPE_WARN;
0201     }
0202 
0203     if (file)
0204         pr_crit("kernel BUG at %s:%u!\n", file, line);
0205     else
0206         pr_crit("Kernel BUG at %pB [verbose debug info unavailable]\n",
0207             (void *)bugaddr);
0208 
0209     return BUG_TRAP_TYPE_BUG;
0210 }
0211 
0212 static void clear_once_table(struct bug_entry *start, struct bug_entry *end)
0213 {
0214     struct bug_entry *bug;
0215 
0216     for (bug = start; bug < end; bug++)
0217         bug->flags &= ~BUGFLAG_DONE;
0218 }
0219 
0220 void generic_bug_clear_once(void)
0221 {
0222 #ifdef CONFIG_MODULES
0223     struct module *mod;
0224 
0225     rcu_read_lock_sched();
0226     list_for_each_entry_rcu(mod, &module_bug_list, bug_list)
0227         clear_once_table(mod->bug_table,
0228                  mod->bug_table + mod->num_bugs);
0229     rcu_read_unlock_sched();
0230 #endif
0231 
0232     clear_once_table(__start___bug_table, __stop___bug_table);
0233 }