18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci Generic support for BUG() 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci This respects the following config options: 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci CONFIG_BUG - emit BUG traps. Nothing happens without this. 88c2ecf20Sopenharmony_ci CONFIG_GENERIC_BUG - enable this code. 98c2ecf20Sopenharmony_ci CONFIG_GENERIC_BUG_RELATIVE_POINTERS - use 32-bit pointers relative to 108c2ecf20Sopenharmony_ci the containing struct bug_entry for bug_addr and file. 118c2ecf20Sopenharmony_ci CONFIG_DEBUG_BUGVERBOSE - emit full file+line information for each BUG 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci CONFIG_BUG and CONFIG_DEBUG_BUGVERBOSE are potentially user-settable 148c2ecf20Sopenharmony_ci (though they're generally always on). 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci CONFIG_GENERIC_BUG is set by each architecture using this code. 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci To use this, your architecture must: 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci 1. Set up the config options: 218c2ecf20Sopenharmony_ci - Enable CONFIG_GENERIC_BUG if CONFIG_BUG 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci 2. Implement BUG (and optionally BUG_ON, WARN, WARN_ON) 248c2ecf20Sopenharmony_ci - Define HAVE_ARCH_BUG 258c2ecf20Sopenharmony_ci - Implement BUG() to generate a faulting instruction 268c2ecf20Sopenharmony_ci - NOTE: struct bug_entry does not have "file" or "line" entries 278c2ecf20Sopenharmony_ci when CONFIG_DEBUG_BUGVERBOSE is not enabled, so you must generate 288c2ecf20Sopenharmony_ci the values accordingly. 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci 3. Implement the trap 318c2ecf20Sopenharmony_ci - In the illegal instruction trap handler (typically), verify 328c2ecf20Sopenharmony_ci that the fault was in kernel mode, and call report_bug() 338c2ecf20Sopenharmony_ci - report_bug() will return whether it was a false alarm, a warning, 348c2ecf20Sopenharmony_ci or an actual bug. 358c2ecf20Sopenharmony_ci - You must implement the is_valid_bugaddr(bugaddr) callback which 368c2ecf20Sopenharmony_ci returns true if the eip is a real kernel address, and it points 378c2ecf20Sopenharmony_ci to the expected BUG trap instruction. 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci Jeremy Fitzhardinge <jeremy@goop.org> 2006 408c2ecf20Sopenharmony_ci */ 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci#define pr_fmt(fmt) fmt 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci#include <linux/list.h> 458c2ecf20Sopenharmony_ci#include <linux/module.h> 468c2ecf20Sopenharmony_ci#include <linux/kernel.h> 478c2ecf20Sopenharmony_ci#include <linux/bug.h> 488c2ecf20Sopenharmony_ci#include <linux/sched.h> 498c2ecf20Sopenharmony_ci#include <linux/rculist.h> 508c2ecf20Sopenharmony_ci#include <linux/ftrace.h> 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ciextern struct bug_entry __start___bug_table[], __stop___bug_table[]; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cistatic inline unsigned long bug_addr(const struct bug_entry *bug) 558c2ecf20Sopenharmony_ci{ 568c2ecf20Sopenharmony_ci#ifndef CONFIG_GENERIC_BUG_RELATIVE_POINTERS 578c2ecf20Sopenharmony_ci return bug->bug_addr; 588c2ecf20Sopenharmony_ci#else 598c2ecf20Sopenharmony_ci return (unsigned long)bug + bug->bug_addr_disp; 608c2ecf20Sopenharmony_ci#endif 618c2ecf20Sopenharmony_ci} 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci#ifdef CONFIG_MODULES 648c2ecf20Sopenharmony_ci/* Updates are protected by module mutex */ 658c2ecf20Sopenharmony_cistatic LIST_HEAD(module_bug_list); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_cistatic struct bug_entry *module_find_bug(unsigned long bugaddr) 688c2ecf20Sopenharmony_ci{ 698c2ecf20Sopenharmony_ci struct module *mod; 708c2ecf20Sopenharmony_ci struct bug_entry *bug = NULL; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci rcu_read_lock_sched(); 738c2ecf20Sopenharmony_ci list_for_each_entry_rcu(mod, &module_bug_list, bug_list) { 748c2ecf20Sopenharmony_ci unsigned i; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci bug = mod->bug_table; 778c2ecf20Sopenharmony_ci for (i = 0; i < mod->num_bugs; ++i, ++bug) 788c2ecf20Sopenharmony_ci if (bugaddr == bug_addr(bug)) 798c2ecf20Sopenharmony_ci goto out; 808c2ecf20Sopenharmony_ci } 818c2ecf20Sopenharmony_ci bug = NULL; 828c2ecf20Sopenharmony_ciout: 838c2ecf20Sopenharmony_ci rcu_read_unlock_sched(); 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci return bug; 868c2ecf20Sopenharmony_ci} 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_civoid module_bug_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs, 898c2ecf20Sopenharmony_ci struct module *mod) 908c2ecf20Sopenharmony_ci{ 918c2ecf20Sopenharmony_ci char *secstrings; 928c2ecf20Sopenharmony_ci unsigned int i; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci lockdep_assert_held(&module_mutex); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci mod->bug_table = NULL; 978c2ecf20Sopenharmony_ci mod->num_bugs = 0; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci /* Find the __bug_table section, if present */ 1008c2ecf20Sopenharmony_ci secstrings = (char *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; 1018c2ecf20Sopenharmony_ci for (i = 1; i < hdr->e_shnum; i++) { 1028c2ecf20Sopenharmony_ci if (strcmp(secstrings+sechdrs[i].sh_name, "__bug_table")) 1038c2ecf20Sopenharmony_ci continue; 1048c2ecf20Sopenharmony_ci mod->bug_table = (void *) sechdrs[i].sh_addr; 1058c2ecf20Sopenharmony_ci mod->num_bugs = sechdrs[i].sh_size / sizeof(struct bug_entry); 1068c2ecf20Sopenharmony_ci break; 1078c2ecf20Sopenharmony_ci } 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci /* 1108c2ecf20Sopenharmony_ci * Strictly speaking this should have a spinlock to protect against 1118c2ecf20Sopenharmony_ci * traversals, but since we only traverse on BUG()s, a spinlock 1128c2ecf20Sopenharmony_ci * could potentially lead to deadlock and thus be counter-productive. 1138c2ecf20Sopenharmony_ci * Thus, this uses RCU to safely manipulate the bug list, since BUG 1148c2ecf20Sopenharmony_ci * must run in non-interruptive state. 1158c2ecf20Sopenharmony_ci */ 1168c2ecf20Sopenharmony_ci list_add_rcu(&mod->bug_list, &module_bug_list); 1178c2ecf20Sopenharmony_ci} 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_civoid module_bug_cleanup(struct module *mod) 1208c2ecf20Sopenharmony_ci{ 1218c2ecf20Sopenharmony_ci lockdep_assert_held(&module_mutex); 1228c2ecf20Sopenharmony_ci list_del_rcu(&mod->bug_list); 1238c2ecf20Sopenharmony_ci} 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci#else 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_cistatic inline struct bug_entry *module_find_bug(unsigned long bugaddr) 1288c2ecf20Sopenharmony_ci{ 1298c2ecf20Sopenharmony_ci return NULL; 1308c2ecf20Sopenharmony_ci} 1318c2ecf20Sopenharmony_ci#endif 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_cistruct bug_entry *find_bug(unsigned long bugaddr) 1348c2ecf20Sopenharmony_ci{ 1358c2ecf20Sopenharmony_ci struct bug_entry *bug; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci for (bug = __start___bug_table; bug < __stop___bug_table; ++bug) 1388c2ecf20Sopenharmony_ci if (bugaddr == bug_addr(bug)) 1398c2ecf20Sopenharmony_ci return bug; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci return module_find_bug(bugaddr); 1428c2ecf20Sopenharmony_ci} 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_cienum bug_trap_type report_bug(unsigned long bugaddr, struct pt_regs *regs) 1458c2ecf20Sopenharmony_ci{ 1468c2ecf20Sopenharmony_ci struct bug_entry *bug; 1478c2ecf20Sopenharmony_ci const char *file; 1488c2ecf20Sopenharmony_ci unsigned line, warning, once, done; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci if (!is_valid_bugaddr(bugaddr)) 1518c2ecf20Sopenharmony_ci return BUG_TRAP_TYPE_NONE; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci bug = find_bug(bugaddr); 1548c2ecf20Sopenharmony_ci if (!bug) 1558c2ecf20Sopenharmony_ci return BUG_TRAP_TYPE_NONE; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci disable_trace_on_warning(); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci file = NULL; 1608c2ecf20Sopenharmony_ci line = 0; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_BUGVERBOSE 1638c2ecf20Sopenharmony_ci#ifndef CONFIG_GENERIC_BUG_RELATIVE_POINTERS 1648c2ecf20Sopenharmony_ci file = bug->file; 1658c2ecf20Sopenharmony_ci#else 1668c2ecf20Sopenharmony_ci file = (const char *)bug + bug->file_disp; 1678c2ecf20Sopenharmony_ci#endif 1688c2ecf20Sopenharmony_ci line = bug->line; 1698c2ecf20Sopenharmony_ci#endif 1708c2ecf20Sopenharmony_ci warning = (bug->flags & BUGFLAG_WARNING) != 0; 1718c2ecf20Sopenharmony_ci once = (bug->flags & BUGFLAG_ONCE) != 0; 1728c2ecf20Sopenharmony_ci done = (bug->flags & BUGFLAG_DONE) != 0; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci if (warning && once) { 1758c2ecf20Sopenharmony_ci if (done) 1768c2ecf20Sopenharmony_ci return BUG_TRAP_TYPE_WARN; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci /* 1798c2ecf20Sopenharmony_ci * Since this is the only store, concurrency is not an issue. 1808c2ecf20Sopenharmony_ci */ 1818c2ecf20Sopenharmony_ci bug->flags |= BUGFLAG_DONE; 1828c2ecf20Sopenharmony_ci } 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci /* 1858c2ecf20Sopenharmony_ci * BUG() and WARN_ON() families don't print a custom debug message 1868c2ecf20Sopenharmony_ci * before triggering the exception handler, so we must add the 1878c2ecf20Sopenharmony_ci * "cut here" line now. WARN() issues its own "cut here" before the 1888c2ecf20Sopenharmony_ci * extra debugging message it writes before triggering the handler. 1898c2ecf20Sopenharmony_ci */ 1908c2ecf20Sopenharmony_ci if ((bug->flags & BUGFLAG_NO_CUT_HERE) == 0) 1918c2ecf20Sopenharmony_ci printk(KERN_DEFAULT CUT_HERE); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci if (warning) { 1948c2ecf20Sopenharmony_ci /* this is a WARN_ON rather than BUG/BUG_ON */ 1958c2ecf20Sopenharmony_ci __warn(file, line, (void *)bugaddr, BUG_GET_TAINT(bug), regs, 1968c2ecf20Sopenharmony_ci NULL); 1978c2ecf20Sopenharmony_ci return BUG_TRAP_TYPE_WARN; 1988c2ecf20Sopenharmony_ci } 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci if (file) 2018c2ecf20Sopenharmony_ci pr_crit("kernel BUG at %s:%u!\n", file, line); 2028c2ecf20Sopenharmony_ci else 2038c2ecf20Sopenharmony_ci pr_crit("Kernel BUG at %pB [verbose debug info unavailable]\n", 2048c2ecf20Sopenharmony_ci (void *)bugaddr); 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci return BUG_TRAP_TYPE_BUG; 2078c2ecf20Sopenharmony_ci} 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_cistatic void clear_once_table(struct bug_entry *start, struct bug_entry *end) 2108c2ecf20Sopenharmony_ci{ 2118c2ecf20Sopenharmony_ci struct bug_entry *bug; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci for (bug = start; bug < end; bug++) 2148c2ecf20Sopenharmony_ci bug->flags &= ~BUGFLAG_DONE; 2158c2ecf20Sopenharmony_ci} 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_civoid generic_bug_clear_once(void) 2188c2ecf20Sopenharmony_ci{ 2198c2ecf20Sopenharmony_ci#ifdef CONFIG_MODULES 2208c2ecf20Sopenharmony_ci struct module *mod; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci rcu_read_lock_sched(); 2238c2ecf20Sopenharmony_ci list_for_each_entry_rcu(mod, &module_bug_list, bug_list) 2248c2ecf20Sopenharmony_ci clear_once_table(mod->bug_table, 2258c2ecf20Sopenharmony_ci mod->bug_table + mod->num_bugs); 2268c2ecf20Sopenharmony_ci rcu_read_unlock_sched(); 2278c2ecf20Sopenharmony_ci#endif 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci clear_once_table(__start___bug_table, __stop___bug_table); 2308c2ecf20Sopenharmony_ci} 231