diff options
author | Rainer Gerhards <rgerhards@adiscon.com> | 2004-11-26 17:56:02 +0000 |
---|---|---|
committer | Rainer Gerhards <rgerhards@adiscon.com> | 2004-11-26 17:56:02 +0000 |
commit | 723c8b552ef0a7b12a772d4ba070bd5f4e1c3b7d (patch) | |
tree | e73fa4364e5de157f61d56b3fd6fd3b75aae0ae4 /ksym.c | |
parent | 0185bdf2af7d54c72dc57cd2fd89d1d8bf0e94f6 (diff) | |
download | rsyslog-723c8b552ef0a7b12a772d4ba070bd5f4e1c3b7d.tar.gz rsyslog-723c8b552ef0a7b12a772d4ba070bd5f4e1c3b7d.tar.xz rsyslog-723c8b552ef0a7b12a772d4ba070bd5f4e1c3b7d.zip |
preparing for packaging
Diffstat (limited to 'ksym.c')
-rw-r--r-- | ksym.c | 901 |
1 files changed, 0 insertions, 901 deletions
diff --git a/ksym.c b/ksym.c deleted file mode 100644 index 0a6d7151..00000000 --- a/ksym.c +++ /dev/null @@ -1,901 +0,0 @@ -/* - ksym.c - functions for kernel address->symbol translation - 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 contains functions which handle the translation of kernel - * numeric addresses into symbols for the klogd utility. - * - * Sat Oct 28 09:00:14 CDT 1995: Dr. Wettstein - * Initial Version. - * - * Fri Nov 24 12:50:52 CST 1995: Dr. Wettstein - * Added VERBOSE_DEBUGGING define to make debugging output more - * manageable. - * - * Added support for verification of the loaded kernel symbols. If - * no version information can be be found in the mapfile a warning - * message is issued but translation will still take place. This - * will be the default case if kernel versions < 1.3.43 are used. - * - * If the symbols in the mapfile are of the same version as the kernel - * that is running an informative message is issued. If the symbols - * in the mapfile do not match the current kernel version a warning - * message is issued and translation is disabled. - * - * Wed Dec 6 16:14:11 CST 1995: Dr. Wettstein - * Added /boot/System.map to the list of symbol maps to search for. - * Also made this map the first item in the search list. I am open - * to CONSTRUCTIVE suggestions for any additions or corrections to - * the list of symbol maps to search for. Be forewarned that the - * list in use is the consensus agreement between myself, Linus and - * some package distributers. It is a given that no list will suit - * everyone's taste. If you have rabid concerns about the list - * please feel free to edit the system_maps array and compile your - * own binaries. - * - * Added support for searching of the list of symbol maps. This - * allows support for access to multiple symbol maps. The theory - * behind this is that a production kernel may have a system map in - * /boot/System.map. If a test kernel is booted this system map - * would be skipped in favor of one found in /usr/src/linux. - * - * Thu Jan 18 11:18:31 CST 1996: Dr. Wettstein - * Added patch from beta-testers to allow for reading of both - * ELF and a.out map files. - * - * Wed Aug 21 09:15:49 CDT 1996: Dr. Wettstein - * Reloading of kernel module symbols is now turned on by the - * SetParanoiaLevel function. The default behavior is to NOT reload - * the kernel module symbols when a protection fault is detected. - * - * Added support for freeing of the current kernel module symbols. - * This was necessary to support reloading of the kernel module symbols. - * - * When a matching static symbol table is loaded the kernel version - * number is printed. - * - * Mon Jun 9 17:12:42 CST 1997: Martin Schulze - * Added #1 and #2 to some error messages in order to being able - * to divide them (ulmo@Q.Net) - * - * Fri Jun 13 10:50:23 CST 1997: Martin Schulze - * Changed definition of LookupSymbol to non-static because it is - * used in klogd.c, too. - * - * Fri Jan 9 23:00:08 CET 1998: Martin Schulze <joey@infodrom.north.de> - * Fixed bug that caused klogd to die if there is no System.map available. - * - * Sun 29 Mar 18:14:07 BST 1998: Mark Simon Phillips <M.S.Phillips@nortel.co.uk> - * Switched to fgets() as gets() is not buffer overrun secure. - * - * Mon Apr 13 18:18:45 CEST 1998: Martin Schulze <joey@infodrom.north.de> - * Modified loop for detecting the correct system map. Now it won't - * stop if a file has been found but doesn't contain the correct map. - * Special thanks go go Mark Simon Phillips for the hint. - * - * Mon Oct 12 00:42:30 CEST 1998: Martin Schulze <joey@infodrom.north.de> - * Modified CheckVersion() - * . Use shift to decode the kernel version - * . Compare integers of kernel version - * . extract major.minor.patch from utsname.release via sscanf() - * The reason lays in possible use of kernel flavours which - * modify utsname.release but no the Version_ symbol. - * - * Sun Feb 21 22:27:49 EST 1999: Keith Owens <kaos@ocs.com.au> - * Fixed bug that caused klogd to die if there is no sym_array available. - * - * Tue Sep 12 23:48:12 CEST 2000: Martin Schulze <joey@infodrom.ffis.de> - * Close symbol file in InitKsyms() when an error occurred. - */ - - -/* Includes. */ -#include <stdlib.h> -#include <malloc.h> -#include <sys/utsname.h> -#include "klogd.h" -#include "ksyms.h" - -#define VERBOSE_DEBUGGING 0 - - -/* Variables static to this module. */ -struct sym_table -{ - unsigned long value; - char *name; -}; - -static int num_syms = 0; -static int i_am_paranoid = 0; -static char vstring[12]; -static struct sym_table *sym_array = (struct sym_table *) 0; - -static char *system_maps[] = -{ - "/boot/System.map", - "/System.map", -#if defined(TEST) - "./System.map", -#endif - (char *) 0 -}; - - -#if defined(TEST) -int debugging; -#else -extern int debugging; -#endif - - -/* Function prototypes. */ -static char * FindSymbolFile(void); -static int AddSymbol(unsigned long, char*); -static void FreeSymbols(void); -static int CheckVersion(char *); -static int CheckMapVersion(char *); - - -/************************************************************************** - * Function: InitKsyms - * - * Purpose: This function is responsible for initializing and loading - * the data tables used by the kernel address translations. - * - * Arguements: (char *) mapfile - * - * mapfile:-> A pointer to a complete path - * specification of the file containing - * the kernel map to use. - * - * Return: int - * - * A boolean style context is returned. The return value will - * be true if initialization was successful. False if not. - **************************************************************************/ - -extern int InitKsyms(mapfile) - - char *mapfile; - -{ - auto char type, - sym[512]; - - auto int version = 0; - - auto unsigned long int address; - - auto FILE *sym_file; - - - /* Check and make sure that we are starting with a clean slate. */ - if ( num_syms > 0 ) - FreeSymbols(); - - - /* - * Search for and open the file containing the kernel symbols. - */ - if ( mapfile != (char *) 0 ) - { - if ( (sym_file = fopen(mapfile, "r")) == (FILE *) 0 ) - { - Syslog(LOG_WARNING, "Cannot open map file: %s.", \ - mapfile); - return(0); - } - } - else - { - if ( (mapfile = FindSymbolFile()) == (char *) 0 ) - { - Syslog(LOG_WARNING, "Cannot find map file."); - if ( debugging ) - fputs("Cannot find map file.\n", stderr); - return(0); - } - - if ( (sym_file = fopen(mapfile, "r")) == (FILE *) 0 ) - { - Syslog(LOG_WARNING, "Cannot open map file."); - if ( debugging ) - fputs("Cannot open map file.\n", stderr); - return(0); - } - } - - - /* - * Read the kernel symbol table file and add entries for each - * line. I suspect that the use of fscanf is not really in vogue - * but it was quick and dirty and IMHO suitable for fixed format - * data such as this. If anybody doesn't agree with this please - * e-mail me a diff containing a parser with suitable political - * correctness -- GW. - */ - while ( !feof(sym_file) ) - { - if ( fscanf(sym_file, "%lx %c %s\n", &address, &type, sym) - != 3 ) - { - Syslog(LOG_ERR, "Error in symbol table input (#1)."); - fclose(sym_file); - return(0); - } - if ( VERBOSE_DEBUGGING && debugging ) - fprintf(stderr, "Address: %lx, Type: %c, Symbol: %s\n", - address, type, sym); - - if ( AddSymbol(address, sym) == 0 ) - { - Syslog(LOG_ERR, "Error adding symbol - %s.", sym); - fclose(sym_file); - return(0); - } - - if ( version == 0 ) - version = CheckVersion(sym); - } - - - Syslog(LOG_INFO, "Loaded %d symbols from %s.", num_syms, mapfile); - switch ( version ) - { - case -1: - Syslog(LOG_WARNING, "Symbols do not match kernel version."); - num_syms = 0; - break; - - case 0: - Syslog(LOG_WARNING, "Cannot verify that symbols match " \ - "kernel version."); - break; - - case 1: - Syslog(LOG_INFO, "Symbols match kernel version %s.", vstring); - break; - } - - fclose(sym_file); - return(1); -} - - -/************************************************************************** - * Function: FindSymbolFile - * - * Purpose: This function is responsible for encapsulating the search - * for a valid symbol file. Encapsulating the search for - * the map file in this function allows an intelligent search - * process to be implemented. - * - * The list of symbol files will be searched until either a - * symbol file is found whose version matches the currently - * executing kernel or the end of the list is encountered. If - * the end of the list is encountered the first available - * symbol file is returned to the caller. - * - * This strategy allows klogd to locate valid symbol files - * for both a production and an experimental kernel. For - * example a map for a production kernel could be installed - * in /boot. If an experimental kernel is loaded the map - * in /boot will be skipped and the map in /usr/src/linux would - * be used if its version number matches the executing kernel. - * - * Arguements: None specified. - * - * Return: char * - * - * If a valid system map cannot be located a null pointer - * is returned to the caller. - * - * If the search is succesful a pointer is returned to the - * caller which points to the name of the file containing - * the symbol table to be used. - **************************************************************************/ - -static char * FindSymbolFile() - -{ - auto char *file = (char *) 0, - **mf = system_maps; - - auto struct utsname utsname; - static char symfile[100]; - - auto FILE *sym_file = (FILE *) 0; - - if ( uname(&utsname) < 0 ) - { - Syslog(LOG_ERR, "Cannot get kernel version information."); - return(0); - } - - if ( debugging ) - fputs("Searching for symbol map.\n", stderr); - - for (mf = system_maps; *mf != (char *) 0 && file == (char *) 0; ++mf) - { - - sprintf (symfile, "%s-%s", *mf, utsname.release); - if ( debugging ) - fprintf(stderr, "Trying %s.\n", symfile); - if ( (sym_file = fopen(symfile, "r")) != (FILE *) 0 ) { - if (CheckMapVersion(symfile) == 1) - file = symfile; - } - if (sym_file == (FILE *) 0 || file == (char *) 0) { - sprintf (symfile, "%s", *mf); - if ( debugging ) - fprintf(stderr, "Trying %s.\n", symfile); - if ( (sym_file = fopen(symfile, "r")) != (FILE *) 0 ) { - if (CheckMapVersion(symfile) == 1) - file = symfile; - } - } - - } - - /* - * At this stage of the game we are at the end of the symbol - * tables. - */ - if ( debugging ) - fprintf(stderr, "End of search list encountered.\n"); - return(file); -} - - -/************************************************************************** - * Function: CheckVersion - * - * Purpose: This function is responsible for determining whether or - * the system map being loaded matches the version of the - * currently running kernel. - * - * The kernel version is checked by examing a variable which - * is of the form: _Version_66347 (a.out) or Version_66437 (ELF). - * - * The suffix of this variable is the current kernel version - * of the kernel encoded in base 256. For example the - * above variable would be decoded as: - * - * (66347 = 1*65536 + 3*256 + 43 = 1.3.43) - * - * (Insert appropriate deities here) help us if Linus ever - * needs more than 255 patch levels to get a kernel out the - * door... :-) - * - * Arguements: (char *) version - * - * version:-> A pointer to the string which - * is to be decoded as a kernel - * version variable. - * - * Return: int - * - * -1:-> The currently running kernel version does - * not match this version string. - * - * 0:-> The string is not a kernel version variable. - * - * 1:-> The executing kernel is of the same version - * as the version string. - **************************************************************************/ - -static int CheckVersion(version) - - char *version; - - -{ - auto int vnum, - major, - minor, - patch; - -#ifndef TESTING - int kvnum; - auto struct utsname utsname; -#endif - - static char *prefix = { "Version_" }; - - - /* Early return if there is no hope. */ - if ( strncmp(version, prefix, strlen(prefix)) == 0 /* ELF */ || - (*version == '_' && - strncmp(++version, prefix, strlen(prefix)) == 0 ) /* a.out */ ) - ; - else - return(0); - - - /* - * Since the symbol looks like a kernel version we can start - * things out by decoding the version string into its component - * parts. - */ - vnum = atoi(version + strlen(prefix)); - patch = vnum & 0x000000FF; - minor = (vnum >> 8) & 0x000000FF; - major = (vnum >> 16) & 0x000000FF; - if ( debugging ) - fprintf(stderr, "Version string = %s, Major = %d, " \ - "Minor = %d, Patch = %d.\n", version + - strlen(prefix), major, minor, \ - patch); - sprintf(vstring, "%d.%d.%d", major, minor, patch); - -#ifndef TESTING - /* - * We should now have the version string in the vstring variable in - * the same format that it is stored in by the kernel. We now - * ask the kernel for its version information and compare the two - * values to determine if our system map matches the kernel - * version level. - */ - if ( uname(&utsname) < 0 ) - { - Syslog(LOG_ERR, "Cannot get kernel version information."); - return(0); - } - if ( debugging ) - fprintf(stderr, "Comparing kernel %s with symbol table %s.\n",\ - utsname.release, vstring); - - if ( sscanf (utsname.release, "%d.%d.%d", &major, &minor, &patch) < 3 ) - { - Syslog(LOG_ERR, "Kernel send bogus release string `%s'.", - utsname.release); - return(0); - } - - /* Compute the version code from data sent by the kernel */ - kvnum = (major << 16) | (minor << 8) | patch; - - /* Failure. */ - if ( vnum != kvnum ) - return(-1); - - /* Success. */ -#endif - return(1); -} - - -/************************************************************************** - * Function: CheckMapVersion - * - * Purpose: This function is responsible for determining whether or - * the system map being loaded matches the version of the - * currently running kernel. It uses CheckVersion as - * backend. - * - * Arguements: (char *) fname - * - * fname:-> A pointer to the string which - * references the system map file to - * be used. - * - * Return: int - * - * -1:-> The currently running kernel version does - * not match the version in the given file. - * - * 0:-> No system map file or no version information. - * - * 1:-> The executing kernel is of the same version - * as the version of the map file. - **************************************************************************/ - -static int CheckMapVersion(fname) - - char *fname; - - -{ - int version; - FILE *sym_file; - auto unsigned long int address; - auto char type, - sym[512]; - - if ( (sym_file = fopen(fname, "r")) != (FILE *) 0 ) { - /* - * At this point a map file was successfully opened. We - * now need to search this file and look for version - * information. - */ - Syslog(LOG_INFO, "Inspecting %s", fname); - - version = 0; - while ( !feof(sym_file) && (version == 0) ) - { - if ( fscanf(sym_file, "%lx %c %s\n", &address, \ - &type, sym) != 3 ) - { - Syslog(LOG_ERR, "Error in symbol table input (#2)."); - fclose(sym_file); - return(0); - } - if ( VERBOSE_DEBUGGING && debugging ) - fprintf(stderr, "Address: %lx, Type: %c, " \ - "Symbol: %s\n", address, type, sym); - - version = CheckVersion(sym); - } - fclose(sym_file); - - switch ( version ) - { - case -1: - Syslog(LOG_ERR, "Symbol table has incorrect " \ - "version number.\n"); - break; - - case 0: - if ( debugging ) - fprintf(stderr, "No version information " \ - "found.\n"); - break; - case 1: - if ( debugging ) - fprintf(stderr, "Found table with " \ - "matching version number.\n"); - break; - } - - return(version); - } - - return(0); -} - - -/************************************************************************** - * Function: AddSymbol - * - * Purpose: This function is responsible for adding a symbol name - * and its address to the symbol table. - * - * Arguements: (unsigned long) address, (char *) symbol - * - * Return: int - * - * A boolean value is assumed. True if the addition is - * successful. False if not. - **************************************************************************/ - -static int AddSymbol(address, symbol) - - unsigned long address; - - char *symbol; - -{ - /* Allocate the the symbol table entry. */ - sym_array = (struct sym_table *) realloc(sym_array, (num_syms+1) * \ - sizeof(struct sym_table)); - if ( sym_array == (struct sym_table *) 0 ) - return(0); - - /* Then the space for the symbol. */ - sym_array[num_syms].name = (char *) malloc(strlen(symbol)*sizeof(char)\ - + 1); - if ( sym_array[num_syms].name == (char *) 0 ) - return(0); - - sym_array[num_syms].value = address; - strcpy(sym_array[num_syms].name, symbol); - ++num_syms; - return(1); -} - - -/************************************************************************** - * Function: LookupSymbol - * - * Purpose: Find the symbol which is related to the given kernel - * address. - * - * 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. - **************************************************************************/ - -char * LookupSymbol(value, sym) - - unsigned long value; - - struct symbol *sym; - -{ - auto int lp; - - auto char *last; - - if (!sym_array) - return((char *) 0); - - last = sym_array[0].name; - sym->offset = 0; - sym->size = 0; - if ( value < sym_array[0].value ) - return((char *) 0); - - for(lp= 0; lp <= num_syms; ++lp) - { - if ( sym_array[lp].value > value ) - { - sym->offset = value - sym_array[lp-1].value; - sym->size = sym_array[lp].value - \ - sym_array[lp-1].value; - return(last); - } - last = sym_array[lp].name; - } - - if ( (last = LookupModuleSymbol(value, sym)) != (char *) 0 ) - return(last); - - return((char *) 0); -} - - -/************************************************************************** - * Function: FreeSymbols - * - * Purpose: This function is responsible for freeing all memory which - * has been allocated to hold the static symbol table. It - * also initializes the symbol count and in general prepares - * for a re-read of a static symbol table. - * - * Arguements: void - * - * Return: void - **************************************************************************/ - -static void FreeSymbols() - -{ - auto int lp; - - /* Free each piece of memory allocated for symbol names. */ - for(lp= 0; lp < num_syms; ++lp) - free(sym_array[lp].name); - - /* Whack the entire array and initialize everything. */ - free(sym_array); - sym_array = (struct sym_table *) 0; - num_syms = 0; - - return; -} - - -/************************************************************************** - * Function: LogExpanded - * - * Purpose: This function is responsible for logging a kernel message - * line after all potential numeric kernel addresses have - * been resolved symolically. - * - * Arguements: (char *) line, (char *) el - * - * line:-> A pointer to the buffer containing the kernel - * message to be expanded and logged. - * - * el:-> A pointer to the buffer into which the expanded - * kernel line will be written. - * - * Return: void - **************************************************************************/ - -extern char * ExpandKadds(line, el) - - char *line; - - char *el; - -{ - auto char dlm, - *kp, - *sl = line, - *elp = el, - *symbol; - - char num[15]; - auto unsigned long int value; - - auto struct symbol sym; - - - /* - * This is as handy a place to put this as anyplace. - * - * Since the insertion of kernel modules can occur in a somewhat - * dynamic fashion we need some mechanism to insure that the - * kernel symbol tables get read just prior to when they are - * needed. - * - * To accomplish this we look for the Oops string and use its - * presence as a signal to load the module symbols. - * - * This is not the best solution of course, especially if the - * kernel is rapidly going out to lunch. What really needs to - * be done is to somehow generate a callback from the - * kernel whenever a module is loaded or unloaded. I am - * open for patches. - */ - if ( i_am_paranoid && - (strstr(line, "Oops:") != (char *) 0) && !InitMsyms() ) - Syslog(LOG_WARNING, "Cannot load kernel module symbols.\n"); - - - /* - * Early return if there do not appear to be any kernel - * messages in this line. - */ - if ( (num_syms == 0) || - (kp = strstr(line, "[<")) == (char *) 0 ) - { - strcpy(el, line); - return(el); - } - - /* Loop through and expand all kernel messages. */ - do - { - while ( sl < kp+1 ) - *elp++ = *sl++; - - /* Now poised at a kernel delimiter. */ - if ( (kp = strstr(sl, ">]")) == (char *) 0 ) - { - strcpy(el, sl); - return(el); - } - dlm = *kp; - strncpy(num,sl+1,kp-sl-1); - num[kp-sl-1] = '\0'; - value = strtoul(num, (char **) 0, 16); - if ( (symbol = LookupSymbol(value, &sym)) == (char *) 0 ) - symbol = sl; - - strcat(elp, symbol); - elp += strlen(symbol); - if ( debugging ) - fprintf(stderr, "Symbol: %s = %lx = %s, %x/%d\n", \ - sl+1, value, \ - (sym.size==0) ? symbol+1 : symbol, \ - sym.offset, sym.size); - - value = 2; - if ( sym.size != 0 ) - { - --value; - ++kp; - elp += sprintf(elp, "+%x/%d", sym.offset, sym.size); - } - strncat(elp, kp, value); - elp += value; - sl = kp + value; - if ( (kp = strstr(sl, "[<")) == (char *) 0 ) - strcat(elp, sl); - } - while ( kp != (char *) 0); - - if ( debugging ) - fprintf(stderr, "Expanded line: %s\n", el); - return(el); -} - - -/************************************************************************** - * Function: SetParanoiaLevel - * - * Purpose: This function is an interface function for setting the - * mode of loadable module symbol lookups. Probably overkill - * but it does slay another global variable. - * - * Arguements: (int) level - * - * level:-> The amount of paranoia which is to be - * present when resolving kernel exceptions. - * Return: void - **************************************************************************/ - -extern void SetParanoiaLevel(level) - - int level; - -{ - i_am_paranoid = level; - return; -} - - -/* - * Setting the -DTEST define enables the following code fragment to - * be compiled. This produces a small standalone program which will - * echo the standard input of the process to stdout while translating - * all numeric kernel addresses into their symbolic equivalent. - */ -#if defined(TEST) - -#include <stdarg.h> - -extern int main(int, char **); - - -extern int main(int argc, char *argv[]) -{ - auto char line[1024], eline[2048]; - - debugging = 1; - - - if ( !InitKsyms((char *) 0) ) - { - fputs("ksym: Error loading system map.\n", stderr); - return(1); - } - - while ( !feof(stdin) ) - { - fgets(line, sizeof(line), stdin); - if (line[strlen(line)-1] == '\n') line[strlen(line)-1] = '\0'; /* Trash NL char */ - memset(eline, '\0', sizeof(eline)); - ExpandKadds(line, eline); - fprintf(stdout, "%s\n", eline); - } - - - 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 |