Patch by Kelledin to use the newer query_module function rather than

the old obsolete hack of stepping thru /dev/kmem.
This commit is contained in:
Joey Schulze 2007-05-25 17:47:16 +00:00
parent b9c89af7a0
commit a0304e96ac

View File

@ -128,6 +128,8 @@ extern int getsyms(struct kernel_sym *);
#define getsyms get_kernel_syms #define getsyms get_kernel_syms
#endif /* __GLIBC__ */ #endif /* __GLIBC__ */
extern int query_module(const char *, int, void *, size_t, size_t *);
/* Variables static to this module. */ /* Variables static to this module. */
struct sym_table struct sym_table
{ {
@ -148,7 +150,7 @@ struct Module
}; };
static int num_modules = 0; static int num_modules = 0;
struct Module *sym_array_modules = (struct Module *) 0; struct Module *sym_array_modules = NULL;
static int have_modules = 0; static int have_modules = 0;
@ -161,8 +163,8 @@ extern int debugging;
/* Function prototypes. */ /* Function prototypes. */
static void FreeModules(void); static void FreeModules(void);
static int AddSymbol(struct Module *mp, unsigned long, char *); static int AddSymbol(struct Module *mp, unsigned long, const char *);
static int AddModule(unsigned long, char *); static int AddModule(char *);
static int symsort(const void *, const void *); static int symsort(const void *, const void *);
@ -185,81 +187,107 @@ static int symsort(const void *, const void *);
extern int InitMsyms() extern int InitMsyms()
{ {
auto int rtn, auto size_t rtn;
tmp; auto int tmp;
auto struct kernel_sym *ksym_table, auto char **mod_table,
*p; **p;
char *modbuf = NULL,
*newbuf;
int modsize = 32,
result;
/* Initialize the kernel module symbol table. */ /* Initialize the kernel module symbol table. */
FreeModules(); FreeModules();
/*
* New style symbol table parser. This uses the newer query_module
* function rather than the old obsolete hack of stepping thru
* /dev/kmem.
*/
/* /*
* The system call which returns the kernel symbol table has * First, we query for the list of loaded modules. We may
* essentialy two modes of operation. Called with a null pointer * have to grow our buffer in size.
* 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 ) do {
{ modsize+=modsize;
if ( errno == ENOSYS ) newbuf=realloc(modbuf, modsize);
Syslog(LOG_INFO, "No module symbols loaded - "
"kernel modules not enabled.\n"); if (newbuf==NULL) {
else /* Well, that sucks. */
Syslog(LOG_ERR, "Error loading kernel symbols " \ Syslog(LOG_ERR, "Error loading kernel symbols " \
"- %s\n", strerror(errno)); "- %s\n", strerror(errno));
if (modbuf!=NULL) free(modbuf);
return(0);
}
modbuf=newbuf;
result=query_module(NULL, QM_MODULES, modbuf, modsize, &rtn);
if (result<0 && errno!=ENOSPC) {
Syslog(LOG_ERR, "Error querying loaded modules " \
"- %s\n", strerror(errno));
free(modbuf);
return(0);
}
} while (result<0);
if ( rtn <= 0 ) {
/* No modules??? */
Syslog(LOG_INFO, "No module symbols loaded - "
"modules disabled?\n");
free(modbuf);
return(0); return(0);
} }
if ( debugging ) if ( debugging )
fprintf(stderr, "Loading kernel module symbols - " fprintf(stderr, "Loading kernel module symbols - "
"Size of table: %d\n", rtn); "Size of table: %d\n", rtn);
ksym_table = (struct kernel_sym *) malloc(rtn * \ mod_table = (char **) malloc(rtn * sizeof(char *));
sizeof(struct kernel_sym)); if ( mod_table == NULL )
if ( ksym_table == (struct kernel_sym *) 0 )
{ {
Syslog(LOG_WARNING, " Failed memory allocation for kernel " \ Syslog(LOG_WARNING, " Failed memory allocation for kernel " \
"symbol table.\n"); "symbol table.\n");
return(0); free(modbuf);
}
if ( (rtn = getsyms(ksym_table)) < 0 )
{
Syslog(LOG_WARNING, "Error reading kernel symbols - %s\n", \
strerror(errno));
return(0); return(0);
} }
sym_array_modules = (struct Module *) malloc(rtn * sizeof(struct Module));
if ( sym_array_modules == NULL )
{
Syslog(LOG_WARNING, " Failed memory allocation for kernel " \
"symbol table.\n");
free(mod_table);
free(modbuf);
return(0);
}
/* /*
* Build a symbol table compatible with the other one used by * Build a symbol table compatible with the other one used by
* klogd. * klogd.
*/ */
tmp = rtn; newbuf=modbuf;
p = ksym_table; for (tmp=rtn-1; tmp>=0; tmp--)
while ( tmp-- )
{ {
if ( !AddModule(p->value, p->name) ) mod_table[tmp]=newbuf;
newbuf+=(strlen(newbuf)+1);
if ( !AddModule(mod_table[tmp]) )
{ {
Syslog(LOG_WARNING, "Error adding kernel module table " Syslog(LOG_WARNING, "Error adding kernel module table "
"entry.\n"); "entry.\n");
free(ksym_table); free(mod_table);
free(modbuf);
return(0); return(0);
} }
++p;
} }
have_modules = 1;
/* Sort the symbol tables in each module. */ /* Sort the symbol tables in each module. */
for (rtn = tmp= 0; tmp < num_modules; ++tmp) for (rtn = tmp= 0; tmp < num_modules; ++tmp)
{ {
@ -277,7 +305,8 @@ extern int InitMsyms()
Syslog(LOG_INFO, "Loaded %d %s from %d module%s", rtn, \ Syslog(LOG_INFO, "Loaded %d %s from %d module%s", rtn, \
(rtn == 1) ? "symbol" : "symbols", \ (rtn == 1) ? "symbol" : "symbols", \
num_modules, (num_modules == 1) ? "." : "s."); num_modules, (num_modules == 1) ? "." : "s.");
free(ksym_table); free(mod_table);
free(modbuf);
return(1); return(1);
} }
@ -322,10 +351,8 @@ static void FreeModules()
/* Check to see if the module symbol tables need to be cleared. */ /* Check to see if the module symbol tables need to be cleared. */
have_modules = 0; have_modules = 0;
if ( num_modules == 0 )
return;
if (sym_array_modules != NULL) {
for (nmods= 0; nmods < num_modules; ++nmods) for (nmods= 0; nmods < num_modules; ++nmods)
{ {
mp = &sym_array_modules[nmods]; mp = &sym_array_modules[nmods];
@ -338,7 +365,9 @@ static void FreeModules()
} }
free(sym_array_modules); free(sym_array_modules);
sym_array_modules = (struct Module *) 0; sym_array_modules = NULL;
}
num_modules = 0; num_modules = 0;
return; return;
} }
@ -350,23 +379,25 @@ static void FreeModules()
* Purpose: This function is responsible for adding a module to * Purpose: This function is responsible for adding a module to
* the list of currently loaded modules. * the list of currently loaded modules.
* *
* Arguements: (unsigned long) address, (char *) symbol * Arguements: (char *) symbol
*
* address:-> The address of the module.
* *
* symbol:-> The name of the module. * symbol:-> The name of the module.
* *
* Return: int * Return: int
**************************************************************************/ **************************************************************************/
static int AddModule(address, symbol) static int AddModule(symbol)
unsigned long address;
char *symbol; char *symbol;
{ {
auto int memfd; size_t rtn;
size_t i;
const char *cbuf;
int symsize=128;
int result;
struct module_symbol *symbuf=NULL,
*newbuf;
auto struct Module *mp; auto struct Module *mp;
@ -375,77 +406,74 @@ static int AddModule(address, symbol)
if ( have_modules ) if ( have_modules )
return(1); return(1);
/* /* We already have space for the module. */
* 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]; mp = &sym_array_modules[num_modules];
if ( (memfd = open("/dev/kmem", O_RDONLY)) < 0 ) if (query_module(symbol, QM_INFO, &sym_array_modules[num_modules].module,
sizeof(struct module), &rtn)<0)
{ {
Syslog(LOG_WARNING, "Error opening /dev/kmem\n"); Syslog(LOG_WARNING, "Error reading module info for %s.\n",
symbol);
return(0); 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. */ /* Save the module name. */
mp->name = (char *) malloc(strlen(&symbol[1]) + 1); mp->name = strdup(symbol);
if ( mp->name == (char *) 0 ) if ( mp->name == NULL )
return(0); return(0);
strcpy(mp->name, &symbol[1]);
mp->num_syms = 0; mp->num_syms = 0;
mp->sym_array = (struct sym_table *) 0; mp->sym_array = NULL;
++num_modules; ++num_modules;
return(1);
/*
* First, we query for the list of exported symbols. We may
* have to grow our buffer in size.
*/
do {
symsize+=symsize;
newbuf=realloc(symbuf, symsize);
if (newbuf==NULL) {
/* Well, that sucks. */
Syslog(LOG_ERR, "Error loading kernel symbols " \
"- %s\n", strerror(errno));
if (symbuf!=NULL) free(symbuf);
return(0);
} }
else
{ symbuf=newbuf;
result=query_module(symbol, QM_SYMBOLS, symbuf, symsize, &rtn);
if (result<0 && errno!=ENOSPC) {
Syslog(LOG_ERR, "Error querying symbol list for %s " \
"- %s\n", symbol, strerror(errno));
free(symbuf);
return(0);
}
} while (result<0);
if ( rtn < 0 ) {
/* No symbols??? */
Syslog(LOG_INFO, "No module symbols loaded - unknown error.\n");
free(symbuf);
return(0);
}
cbuf=(char *)symbuf;
for (i=0; i<rtn; i++) {
if (num_modules > 0) if (num_modules > 0)
mp = &sym_array_modules[num_modules - 1]; mp = &sym_array_modules[num_modules - 1];
else else
mp = &sym_array_modules[0]; mp = &sym_array_modules[0];
AddSymbol(mp, address, symbol);
AddSymbol(mp, symbuf[i].value,
cbuf+(unsigned long)(symbuf[i].name));
} }
free(symbuf);
return(1); return(1);
} }
@ -477,7 +505,7 @@ static int AddSymbol(mp, address, symbol)
unsigned long address; unsigned long address;
char *symbol; const char *symbol;
{ {
auto int tmp; auto int tmp;