/*------------------------------------------------------------------------------------------*\ * * Copyright (C) 2014 AVM GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * mips-function for BUG() about bug_table \*------------------------------------------------------------------------------------------*/ #include #include #include #include /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ #ifdef CONFIG_BUG_EXTRA_INFO extern unsigned long __start___bug_debug_table; extern unsigned long __stop___bug_debug_table; /*--- #define DEBUG_BUGINFO ---*/ #if defined(DEBUG_BUGINFO) #define DBG_TRC(args...) printk(KERN_INFO args) #else/*--- #if defined(DEBUG_BUGINFO) ---*/ #define DBG_TRC(args...) #endif/*--- #else ---*//*--- #if defined(DEBUG_BUGINFO) ---*/ #define MAX_BUG_TABLES 40 struct bug_debug_tables { char *name; struct bug_debug_table_entry *start; struct bug_debug_table_entry *stop; } bug_debug_table[MAX_BUG_TABLES] = { [0] = { .name = "kernel", .start = (struct bug_debug_table_entry *)&__start___bug_debug_table, .stop = (struct bug_debug_table_entry *)&__stop___bug_debug_table } }; __asm__( " .section __bug_debug_table, \"a\"\n" " .previous \n"); #if defined(DEBUG_BUGINFO) /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static void display_bug_table(struct bug_debug_tables *T) { const struct bug_debug_table_entry *e; unsigned int i = 0; printk(KERN_ERR "%s: '%s' num_entries=%u\n", __func__, T->name, (T->stop - T->start)); for(e = T->start ; e < T->stop ; e++) { printk(KERN_ERR "TABLE[%02u] %p BUG%s(%s) at function '%s' line: %d file: %s\n", i++, e, e->condition ? "_ON" : "", e->condition ? e->condition : "", e->functionname, e->line, e->filename); if(i > 500) { printk(KERN_ERR "...\n"); break; } } } #endif/*--- #if defined(DEBUG_BUGINFO) ---*/ /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ void register_bug_debug_table(char *name, unsigned long start, unsigned long end) { unsigned int i; for(i = 0 ; i < MAX_BUG_TABLES ; i++) { struct bug_debug_tables *T = &bug_debug_table[i]; if(T->name == NULL) { DBG_TRC("[%s][%02u] name='%s' 0x%lx - 0x%lx\n", __FUNCTION__, i, name, start, end); T->name = name; T->start = (struct bug_debug_table_entry *)start; T->stop = (struct bug_debug_table_entry *)end; #if defined(DEBUG_BUGINFO) display_bug_table(T); #endif/*--- #if defined(DEBUG_BUGINFO) ---*/ return; } } printk(KERN_ERR"%s: error: '%s' not allocated!\n", __func__, name); } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ void release_bug_debug_table(char *name) { unsigned int i; DBG_TRC("%s: '%s'\n", __func__, name); for(i = 0 ; i < MAX_BUG_TABLES ; i++) { struct bug_debug_tables *T = &bug_debug_table[i]; if(T->name == name) { T->name = NULL; T->start = (struct bug_debug_table_entry *)0UL; T->stop = (struct bug_debug_table_entry *)0UL; return; } } printk(KERN_ERR"%s: warning: '%s' not found! (driver maybe bugfree)\n", __func__, name); } EXPORT_SYMBOL(register_bug_debug_table); EXPORT_SYMBOL(release_bug_debug_table); /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static const struct bug_debug_table_entry *search_bug_debug_tables(unsigned long addr) { const struct bug_debug_table_entry *e; unsigned int i; /*--- printk(KERN_ERR "[%s] addr 0x%lx %s", __FUNCTION__, addr, addr & 0x1 ? "(mips16)" : ""); ---*/ addr &= ~0x1; for(i = 0 ; i < MAX_BUG_TABLES ; i++) { struct bug_debug_tables *T = &bug_debug_table[i]; /*--- printk(KERN_ERR "[%s] '%s' search from 0x%p to 0x%p\n", __FUNCTION__, T->name, T->start, T->stop); ---*/ if(T->name == NULL) continue; for(e = T->start ; e < T->stop ; e++) { /*--- if(i == 1) ---*/ /*--- printk(KERN_ERR "[%s] '%s' addr 0x%lx e->addr 0x%lx\n", __FUNCTION__, T->name, addr, e->addr); ---*/ if(e->addr + 4 == addr) { /*--- printk(KERN_ERR "[%s] found: '%s' addr 0x%lx + 4 == e->addr 0x%lx\n", __FUNCTION__, T->name, addr, e->addr); ---*/ return e; } if(e->addr == addr) { /*--- printk(KERN_ERR "[%s] found: '%s' addr 0x%lx == e->addr 0x%lx\n", __FUNCTION__, T->name, addr, e->addr); ---*/ return e; } } } return NULL; } #endif/*--- #ifdef CONFIG_BUG_EXTRA_INFO ---*/ /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ void show_bug_by_bugtable(struct pt_regs *regs) { #ifdef CONFIG_BUG_EXTRA_INFO const struct bug_debug_table_entry *bug_info = search_bug_debug_tables(regs->cp0_epc); if(bug_info) { printk(KERN_ERR "BUG%s(%s) at function '%s' line: %d file: %s\n", bug_info->condition ? "_ON" : "", bug_info->condition ? bug_info->condition : "", bug_info->functionname, bug_info->line, bug_info->filename); } else { printk(KERN_ERR "BUG() no bug_debug_table_entry found\n"); } #endif /*--- #ifdef CONFIG_BUG_EXTRA_INFO ---*/ } #if defined(DEBUG_BUGINFO) static int __init display_kernel_buginfolist(void) { display_bug_table(&bug_debug_table[0]); return 0; } late_initcall(display_kernel_buginfolist); #endif