diff options
Diffstat (limited to 'ksym_mod.c')
-rw-r--r-- | ksym_mod.c | 700 |
1 files changed, 0 insertions, 700 deletions
diff --git a/ksym_mod.c b/ksym_mod.c deleted file mode 100644 index 344963b2..00000000 --- a/ksym_mod.c +++ /dev/null @@ -1,700 +0,0 @@ -/* - ksym_mod.c - functions for building symbol lookup tables for klogd - Copyright (c) 1995, 1996 Dr. G.W. Wettstein <greg@wind.rmcc.com> - Copyright (c) 1996 Enjellic Systems Development - - This file is part of the sysklogd package, a kernel and system log daemon. - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* - * This file implements functions which are useful for building - * a symbol lookup table based on the in kernel symbol table - * maintained by the Linux kernel. - * - * Proper logging of kernel panics generated by loadable modules - * tends to be difficult. Since the modules are loaded dynamically - * their addresses are not known at kernel load time. A general - * protection fault (Oops) cannot be properly deciphered with - * classic methods using the static symbol map produced at link time. - * - * One solution to this problem is to have klogd attempt to translate - * addresses from module when the fault occurs. By referencing the - * the kernel symbol table proper resolution of these symbols is made - * possible. - * - * At least that is the plan. - * - * Wed Aug 21 09:20:09 CDT 1996: Dr. Wettstein - * The situation where no module support has been compiled into a - * kernel is now detected. An informative message is output indicating - * that the kernel has no loadable module support whenever kernel - * module symbols are loaded. - * - * An informative message is printed indicating the number of kernel - * modules and the number of symbols loaded from these modules. - * - * Sun Jun 15 16:23:29 MET DST 1997: Michael Alan Dorman - * Some more glibc patches made by <mdorman@debian.org>. - * - * Sat Jan 10 15:00:18 CET 1998: Martin Schulze <joey@infodrom.north.de> - * Fixed problem with klogd not being able to be built on a kernel - * newer than 2.1.18. It was caused by modified structures - * inside the kernel that were included. I have worked in a - * patch from Alessandro Suardi <asuardi@uninetcom.it>. - * - * Sun Jan 25 20:57:34 CET 1998: Martin Schulze <joey@infodrom.north.de> - * Another patch for Linux/alpha by Christopher C Chimelis - * <chris@classnet.med.miami.edu>. - * - * Thu Mar 19 23:39:29 CET 1998: Manuel Rodrigues <pmanuel@cindy.fe.up.pt> - * Changed lseek() to llseek() in order to support > 2GB address - * space which provided by kernels > 2.1.70. - * - * Mon Apr 13 18:18:45 CEST 1998: Martin Schulze <joey@infodrom.north.de> - * Removed <sys/module.h> as it's no longer part of recent glibc - * versions. Added prototyp for llseek() which has been - * forgotton in <unistd.h> from glibc. Added more log - * information if problems occurred while reading a system map - * file, by submission from Mark Simon Phillips <M.S.Phillips@nortel.co.uk>. - * - * Sun Jan 3 18:38:03 CET 1999: Martin Schulze <joey@infodrom.north.de> - * Corrected return value of AddModule if /dev/kmem can't be - * loaded. This will prevent klogd from segfaulting if /dev/kmem - * is not available. Patch from Topi Miettinen <tom@medialab.sonera.net>. - * - * Tue Sep 12 23:11:13 CEST 2000: Martin Schulze <joey@infodrom.ffis.de> - * Changed llseek() to lseek64() in order to skip a libc warning. - */ - - -/* Includes. */ -#include <stdlib.h> -#include <malloc.h> -#include <unistd.h> -#include <signal.h> -#include <errno.h> -#include <sys/fcntl.h> -#include <sys/stat.h> -#if !defined(__GLIBC__) -#include <linux/time.h> -#include <linux/module.h> -#else /* __GLIBC__ */ -#include <linux/module.h> -extern __off64_t lseek64 __P ((int __fd, __off64_t __offset, int __whence)); -extern int get_kernel_syms __P ((struct kernel_sym *__table)); -#endif /* __GLIBC__ */ -#include <stdarg.h> -#include <paths.h> -#include <linux/version.h> - -#include "klogd.h" -#include "ksyms.h" - - -#if !defined(__GLIBC__) -/* - * The following bit uses some kernel/library magic to product what - * looks like a function call to user level code. This function is - * actually a system call in disguise. The purpose of the getsyms - * call is to return a current copy of the in-kernel symbol table. - */ -#define __LIBRARY__ -#include <linux/unistd.h> -#define __NR_getsyms __NR_get_kernel_syms -_syscall1(int, getsyms, struct kernel_sym *, syms); -#undef __LIBRARY__ -extern int getsyms(struct kernel_sym *); -#else /* __GLIBC__ */ -#define getsyms get_kernel_syms -#endif /* __GLIBC__ */ - -/* Variables static to this module. */ -struct sym_table -{ - unsigned long value; - char *name; -}; - -struct Module -{ - struct sym_table *sym_array; - int num_syms; - - char *name; - struct module module; -#if LINUX_VERSION_CODE >= 0x20112 - struct module_info module_info; -#endif -}; - -static int num_modules = 0; -struct Module *sym_array_modules = (struct Module *) 0; - -static int have_modules = 0; - -#if defined(TEST) -static int debugging = 1; -#else -extern int debugging; -#endif - - -/* Function prototypes. */ -static void FreeModules(void); -static int AddSymbol(struct Module *mp, unsigned long, char *); -static int AddModule(unsigned long, char *); -static int symsort(const void *, const void *); - - -/************************************************************************** - * Function: InitMsyms - * - * Purpose: This function is responsible for building a symbol - * table which can be used to resolve addresses for - * loadable modules. - * - * Arguements: Void - * - * Return: A boolean return value is assumed. - * - * A false value indicates that something went wrong. - * - * True if loading is successful. - **************************************************************************/ - -extern int InitMsyms() - -{ - auto int rtn, - tmp; - - auto struct kernel_sym *ksym_table, - *p; - - - /* Initialize the kernel module symbol table. */ - FreeModules(); - - - /* - * The system call which returns the kernel symbol table has - * essentialy two modes of operation. Called with a null pointer - * the system call returns the number of symbols defined in the - * the table. - * - * The second mode of operation is to pass a valid pointer to - * the call which will then load the current symbol table into - * the memory provided. - * - * Returning the symbol table is essentially an all or nothing - * proposition so we need to pre-allocate enough memory for the - * complete table regardless of how many symbols we need. - * - * Bummer. - */ - if ( (rtn = getsyms((struct kernel_sym *) 0)) < 0 ) - { - if ( errno == ENOSYS ) - Syslog(LOG_INFO, "No module symbols loaded - " - "kernel modules not enabled.\n"); - else - Syslog(LOG_ERR, "Error loading kernel symbols " \ - "- %s\n", strerror(errno)); - return(0); - } - if ( debugging ) - fprintf(stderr, "Loading kernel module symbols - " - "Size of table: %d\n", rtn); - - ksym_table = (struct kernel_sym *) malloc(rtn * \ - sizeof(struct kernel_sym)); - if ( ksym_table == (struct kernel_sym *) 0 ) - { - Syslog(LOG_WARNING, " Failed memory allocation for kernel " \ - "symbol table.\n"); - return(0); - } - if ( (rtn = getsyms(ksym_table)) < 0 ) - { - Syslog(LOG_WARNING, "Error reading kernel symbols - %s\n", \ - strerror(errno)); - return(0); - } - - - /* - * Build a symbol table compatible with the other one used by - * klogd. - */ - tmp = rtn; - p = ksym_table; - while ( tmp-- ) - { - if ( !AddModule(p->value, p->name) ) - { - Syslog(LOG_WARNING, "Error adding kernel module table " - "entry.\n"); - free(ksym_table); - return(0); - } - ++p; - } - - /* Sort the symbol tables in each module. */ - for (rtn = tmp= 0; tmp < num_modules; ++tmp) - { - rtn += sym_array_modules[tmp].num_syms; - if ( sym_array_modules[tmp].num_syms < 2 ) - continue; - qsort(sym_array_modules[tmp].sym_array, \ - sym_array_modules[tmp].num_syms, \ - sizeof(struct sym_table), symsort); - } - - if ( rtn == 0 ) - Syslog(LOG_INFO, "No module symbols loaded."); - else - Syslog(LOG_INFO, "Loaded %d %s from %d module%s", rtn, \ - (rtn == 1) ? "symbol" : "symbols", \ - num_modules, (num_modules == 1) ? "." : "s."); - free(ksym_table); - return(1); -} - - -static int symsort(p1, p2) - - const void *p1; - - const void *p2; - -{ - auto const struct sym_table *sym1 = p1, - *sym2 = p2; - - if ( sym1->value < sym2->value ) - return(-1); - if ( sym1->value == sym2->value ) - return(0); - return(1); -} - - -/************************************************************************** - * Function: FreeModules - * - * Purpose: This function is used to free all memory which has been - * allocated for the modules and their symbols. - * - * Arguements: None specified. - * - * Return: void - **************************************************************************/ - -static void FreeModules() - -{ - auto int nmods, - nsyms; - - auto struct Module *mp; - - - /* Check to see if the module symbol tables need to be cleared. */ - have_modules = 0; - if ( num_modules == 0 ) - return; - - - for (nmods= 0; nmods < num_modules; ++nmods) - { - mp = &sym_array_modules[nmods]; - if ( mp->num_syms == 0 ) - continue; - - for (nsyms= 0; nsyms < mp->num_syms; ++nsyms) - free(mp->sym_array[nsyms].name); - free(mp->sym_array); - } - - free(sym_array_modules); - sym_array_modules = (struct Module *) 0; - num_modules = 0; - return; -} - - -/************************************************************************** - * Function: AddModule - * - * Purpose: This function is responsible for adding a module to - * the list of currently loaded modules. - * - * Arguements: (unsigned long) address, (char *) symbol - * - * address:-> The address of the module. - * - * symbol:-> The name of the module. - * - * Return: int - **************************************************************************/ - -static int AddModule(address, symbol) - - unsigned long address; - - char *symbol; - -{ - auto int memfd; - - auto struct Module *mp; - - - /* Return if we have loaded the modules. */ - if ( have_modules ) - return(1); - - /* - * The following section of code is responsible for determining - * whether or not we are done reading the list of modules. - */ - if ( symbol[0] == '#' ) - { - - if ( symbol[1] == '\0' ) - { - /* - * A symbol which consists of a # sign only - * signifies a a resident kernel segment. When we - * hit one of these we are done reading the - * module list. - */ - have_modules = 1; - return(1); - } - /* Allocate space for the module. */ - sym_array_modules = (struct Module *) \ - realloc(sym_array_modules, \ - (num_modules+1) * sizeof(struct Module)); - if ( sym_array_modules == (struct Module *) 0 ) - { - Syslog(LOG_WARNING, "Cannot allocate Module array.\n"); - return(0); - } - mp = &sym_array_modules[num_modules]; - - if ( (memfd = open("/dev/kmem", O_RDONLY)) < 0 ) - { - Syslog(LOG_WARNING, "Error opening /dev/kmem\n"); - return(0); - } - if ( lseek64(memfd, address, SEEK_SET) < 0 ) - { - Syslog(LOG_WARNING, "Error seeking in /dev/kmem\n"); - Syslog(LOG_WARNING, "Symbol %s, value %08x\n", symbol, address); - return(0); - } - if ( read(memfd, \ - (char *)&sym_array_modules[num_modules].module, \ - sizeof(struct module)) < 0 ) - { - Syslog(LOG_WARNING, "Error reading module " - "descriptor.\n"); - return(0); - } - close(memfd); - - /* Save the module name. */ - mp->name = (char *) malloc(strlen(&symbol[1]) + 1); - if ( mp->name == (char *) 0 ) - return(0); - strcpy(mp->name, &symbol[1]); - - mp->num_syms = 0; - mp->sym_array = (struct sym_table *) 0; - ++num_modules; - return(1); - } - else - { - if (num_modules > 0) - mp = &sym_array_modules[num_modules - 1]; - else - mp = &sym_array_modules[0]; - AddSymbol(mp, address, symbol); - } - - - return(1); -} - - -/************************************************************************** - * Function: AddSymbol - * - * Purpose: This function is responsible for adding a symbol name - * and its address to the symbol table. - * - * Arguements: (struct Module *) mp, (unsigned long) address, (char *) symbol - * - * mp:-> A pointer to the module which the symbol is - * to be added to. - * - * address:-> The address of the symbol. - * - * symbol:-> The name of the symbol. - * - * Return: int - * - * A boolean value is assumed. True if the addition is - * successful. False if not. - **************************************************************************/ - -static int AddSymbol(mp, address, symbol) - - struct Module *mp; - - unsigned long address; - - char *symbol; - -{ - auto int tmp; - - - /* Allocate space for the symbol table entry. */ - mp->sym_array = (struct sym_table *) realloc(mp->sym_array, \ - (mp->num_syms+1) * sizeof(struct sym_table)); - if ( mp->sym_array == (struct sym_table *) 0 ) - return(0); - - /* Then the space for the symbol. */ - tmp = strlen(symbol); - tmp += (strlen(mp->name) + 1); - mp->sym_array[mp->num_syms].name = (char *) malloc(tmp + 1); - if ( mp->sym_array[mp->num_syms].name == (char *) 0 ) - return(0); - memset(mp->sym_array[mp->num_syms].name, '\0', tmp + 1); - - /* Stuff interesting information into the module. */ - mp->sym_array[mp->num_syms].value = address; - strcpy(mp->sym_array[mp->num_syms].name, mp->name); - strcat(mp->sym_array[mp->num_syms].name, ":"); - strcat(mp->sym_array[mp->num_syms].name, symbol); - ++mp->num_syms; - - return(1); -} - - -/************************************************************************** - * Function: LookupModuleSymbol - * - * Purpose: Find the symbol which is related to the given address from - * a kernel module. - * - * Arguements: (long int) value, (struct symbol *) sym - * - * value:-> The address to be located. - * - * sym:-> A pointer to a structure which will be - * loaded with the symbol's parameters. - * - * Return: (char *) - * - * If a match cannot be found a diagnostic string is printed. - * If a match is found the pointer to the symbolic name most - * closely matching the address is returned. - **************************************************************************/ - -extern char * LookupModuleSymbol(value, sym) - - unsigned long value; - - struct symbol *sym; - -{ - auto int nmod, - nsym; - - auto struct sym_table *last; - - auto struct Module *mp; - - - sym->size = 0; - sym->offset = 0; - if ( num_modules == 0 ) - return((char *) 0); - - for(nmod= 0; nmod < num_modules; ++nmod) - { - mp = &sym_array_modules[nmod]; - - /* - * Run through the list of symbols in this module and - * see if the address can be resolved. - */ - for(nsym= 1, last = &mp->sym_array[0]; - nsym < mp->num_syms; - ++nsym) - { - if ( mp->sym_array[nsym].value > value ) - { - sym->offset = value - last->value; - sym->size = mp->sym_array[nsym].value - \ - last->value; - return(last->name); - } - last = &mp->sym_array[nsym]; - } - - - /* - * At this stage of the game we still cannot give up the - * ghost. There is the possibility that the address is - * from a module which has no symbols registered with - * the kernel. The solution is to compare the address - * against the starting address and extant of the module - * If it is in this range we can at least return the - * name of the module. - */ -#if LINUX_VERSION_CODE < 0x20112 - if ( (void *) value >= mp->module.addr && - (void *) value <= (mp->module.addr + \ - mp->module.size * 4096) ) -#else - if ( value >= mp->module_info.addr && - value <= (mp->module_info.addr + \ - mp->module.size * 4096) ) -#endif - { - /* - * A special case needs to be checked for. The above - * conditional tells us that we are within the - * extant of this module but symbol lookup has - * failed. - * - * We need to check to see if any symbols have - * been defined in this module. If there have been - * symbols defined the assumption must be made that - * the faulting address lies somewhere beyond the - * last symbol. About the only thing we can do - * at this point is use an offset from this - * symbol. - */ - if ( mp->num_syms > 0 ) - { - last = &mp->sym_array[mp->num_syms - 1]; -#if LINUX_VERSION_CODE < 0x20112 - sym->size = (int) mp->module.addr + \ - (mp->module.size * 4096) - value; -#else - sym->size = (int) mp->module_info.addr + \ - (mp->module.size * 4096) - value; -#endif - sym->offset = value - last->value; - return(last->name); - } - - /* - * There were no symbols defined for this module. - * Return the module name and the offset of the - * faulting address in the module. - */ - sym->size = mp->module.size * 4096; -#if LINUX_VERSION_CODE < 0x20112 - sym->offset = (void *) value - mp->module.addr; -#else - sym->offset = value - mp->module_info.addr; -#endif - return(mp->name); - } - } - - /* It has been a hopeless exercise. */ - return((char *) 0); -} - - -/* - * Setting the -DTEST define enables the following code fragment to - * be compiled. This produces a small standalone program which will - * dump the current kernel symbol table. - */ -#if defined(TEST) - -#include <stdarg.h> - - -extern int main(int, char **); - - -int main(argc, argv) - - int argc; - - char *argv[]; - -{ - auto int lp, syms; - - - if ( !InitMsyms() ) - { - fprintf(stderr, "Cannot load module symbols.\n"); - return(1); - } - - printf("Number of modules: %d\n\n", num_modules); - - for(lp= 0; lp < num_modules; ++lp) - { - printf("Module #%d = %s, Number of symbols = %d\n", lp + 1, \ - sym_array_modules[lp].name, \ - sym_array_modules[lp].num_syms); - - for (syms= 0; syms < sym_array_modules[lp].num_syms; ++syms) - { - printf("\tSymbol #%d\n", syms + 1); - printf("\tName: %s\n", \ - sym_array_modules[lp].sym_array[syms].name); - printf("\tAddress: %lx\n\n", \ - sym_array_modules[lp].sym_array[syms].value); - } - } - - FreeModules(); - return(0); -} - -extern void Syslog(int priority, char *fmt, ...) - -{ - va_list ap; - - va_start(ap, fmt); - fprintf(stdout, "Pr: %d, ", priority); - vfprintf(stdout, fmt, ap); - va_end(ap); - fputc('\n', stdout); - - return; -} - -#endif |