/* Display the symbols exported from the running kernel. Copyright 1996, 1997 Linux International. New implementation contributed by Richard Henderson <rth@tamu.edu> Based on original work by Bjorn Eckwall <bj0rn@blox.se> This file is part of the Linux modutils. 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. */ #ident "$Id: ksyms.c,v 1.1.1.1 1998/01/06 20:51:07 ewt Exp $" #include <sys/types.h> #include <stdio.h> #include <errno.h> #include <unistd.h> #include <fcntl.h> #include <stdlib.h> #include <string.h> #include "module.h" #include "util.h" #include "version.h" #include "logger.h" /*======================================================================*/ int flag_allsyms = 0; int flag_mod_info = 0; int flag_print_header = 1; /*======================================================================*/ static inline void print_symbol(const char *name, unsigned long value, const char *module) { if (module) printf("%0*lx %-32s [%s]\n", (int)(2*sizeof(void*)), value, name, module); else printf("%0*lx %-32s\n", (int)(2*sizeof(void*)), value, name); } static inline void print_mod_info(const char *module, unsigned long addr, unsigned long size) { int o; o = printf("%0*lx (%luk)", (int)(2*sizeof(void*)), addr, (size / 1024) + ((size % 1024) != 0)); o = 2*sizeof(void*)+2+32+2 - o; printf("%*s[%s]\n", o, "", module); } /* If we don't have query_module()... */ static int old_ksyms(void) { struct old_kernel_sym *ksyms, *k; int nsyms, i; int kmem_fd = -1; const char *module; nsyms = get_kernel_syms(NULL); if (nsyms < 0) { perror("get_kernel_syms"); return 1; } ksyms = xmalloc(nsyms * sizeof(*ksyms)); if (get_kernel_syms(ksyms) != nsyms) { fprintf(stderr, "Inconsistency reading kernel symbols -- " "is someone else playing with modules?\n"); return 1; } /* If requested, open kmem so we can get at module information. */ if (flag_mod_info) { kmem_fd = open("/dev/kmem", O_RDONLY); if (kmem_fd < 0) { perror("ksyms: open /dev/kmem"); return 1; } } module = NULL; for (k = ksyms, i = 0; i < nsyms; ++i, ++k) if (k->name[0] == '#') { if (k->name[1]) { module = &k->name[1]; if (flag_mod_info) { struct old_module info; if (llseek(kmem_fd, (off_t)k->value, SEEK_SET) == -1 || read(kmem_fd, &info, sizeof(info)) != sizeof(info)) { perror("ksyms: /dev/kmem"); return 1; } print_mod_info(module, info.addr, info.size * getpagesize()); } } else { if (!flag_allsyms) break; module = NULL; } } else print_symbol(k->name, k->value, module); free(ksyms); if (flag_mod_info) close(kmem_fd); return 0; } /* If we do have query_module()... */ static int new_ksyms(void) { char *modules; size_t nmodules; struct new_module_symbol *syms; size_t nsymbols; ssize_t ret; size_t bufsize; size_t i, j; char *m; struct new_module_symbol *s; /* Query for the module names. */ modules = xmalloc(bufsize = 256); retry_modules_load: if (query_module(NULL, QM_MODULES, modules, bufsize, &ret)) { if (errno == ENOSPC) { modules = xrealloc(modules, bufsize = ret); goto retry_modules_load; } perror("ksyms: QM_MODULES"); return 1; } nmodules = ret; /* Iterate over the modules, in order, and care for their symbols. */ syms = xmalloc(bufsize = 16*1024); for (i = 0, m = modules; i < nmodules; ++i, m += strlen(m)+1) { if (flag_mod_info) { struct new_module_info info; if (query_module(m, QM_INFO, &info, sizeof(info), &ret)) { if (errno == ENOENT) { /* The module must have been removed in the interim: skip */ continue; } perror("ksyms: QM_INFO"); return 1; } print_mod_info(m, info.addr, info.size); } retry_mod_symbol_load: if (query_module(m, QM_SYMBOLS, syms, bufsize, &ret)) switch (errno) { case ENOSPC: syms = xrealloc(syms, bufsize = ret); goto retry_mod_symbol_load; case ENOENT: continue; default: perror("ksyms: QM_SYMBOLS"); return 1; } nsymbols = ret; for (j = 0, s = syms; j < nsymbols; ++j, ++s) print_symbol((char *)syms + s->name, s->value, m); } /* Now do the kernel itself. */ if (flag_allsyms) { retry_kern_symbol_load: if (query_module(NULL, QM_SYMBOLS, syms, bufsize, &ret)) { if (errno == ENOSPC) { syms = xrealloc(syms, bufsize = ret); goto retry_kern_symbol_load; } perror("ksyms: QM_SYMBOLS"); return 1; } nsymbols = ret; for (j = 0, s = syms; j < nsymbols; ++j, ++s) print_symbol((char *)syms + s->name, s->value, NULL); } free(modules); free(syms); return 0; } /*======================================================================*/ int main(int argc, char **argv) { int i; error_file = "ksyms"; while ((i = getopt(argc, argv, "amhV")) != EOF) switch (i) { case 'a': flag_allsyms = 1; break; case 'm': flag_mod_info = 1; break; case 'h': flag_print_header = 0; break; case 'V': fputs("ksyms version " MODUTILS_VERSION "\n", stderr); break; } if (flag_print_header) printf("%-*s %-32s Defined by\n", (int)(2*sizeof(void*)), "Address", "Symbol"); if (query_module(NULL, 0, NULL, 0, NULL) == 0) return new_ksyms(); else return old_ksyms(); }