📄 ksym.c
字号:
/* 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;#elseextern 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -