home *** CD-ROM | disk | FTP | other *** search
/ PC-Online 1996 May / PCOnline_05_1996.bin / linux / source / a / bin / modules-.2 / modules- / modules-1.2.8 / insmod / insmod.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-31  |  31.0 KB  |  1,343 lines

  1. /*
  2.  * Install a module in the kernel.
  3.  *
  4.  * See the file COPYING for your rights (GNU GPL)
  5.  *
  6.  * Originally by Anonymous (as far as I know...)
  7.  * Linux version by Bas Laarhoven <bas@vimec.nl>
  8.  * Modified by Jon Tombs.
  9.  *
  10.  * Support for transient and resident symbols
  11.  * added by Bjorn Ekwall <bj0rn@blox.se> in June 1994 (C)
  12.  *
  13.  * Load map option conceived by Derek Atkins <warlord@MIT.EDU>
  14.  *
  15.  * Support for versioned kernels and symbols: Bjorn Ekwall in December 1994
  16.  *
  17.  * Merged in ksyms and rmmod in December 1994: Bjorn Ekwall
  18.  *
  19.  * Support for ELF modules: Bjorn Ekwall in December 1994 after having
  20.  *                          mangled sources from, and been enlightened
  21.  *                          and supported by Eric Youngdale <eric@aib.com>
  22.  *                          (the kludges are all mine, don't blame Eric...)
  23.  *
  24.  * Support for array initializers: Bjorn Ekwall in January 1995
  25.  * Support for string initializers: Bjorn Ekwall in January 1995
  26.  * Fixed major bug in a.out bss variable handling: March '95, Bas.
  27.  * ELF fixes from H.J.Lu <hjl@nynexst.com>
  28.  * Many ELF and other fixes from:
  29.  *     James Bottomley <J.E.J.Bottomley@damtp.cambridge.ac.uk>
  30.  * Full support for MODPATH setting: Henrik Storner <storner@osiris.ping.dk>
  31.  * Removed limitation of unversioned module vs. versioned kernel: Bjorn
  32.  * Handle all combinations of ELF vs a.out kernels/modules: Bjorn
  33.  * Added syslog error reporting with option "-s": Jacques Gelinas
  34.  * Added MOD_AUTOCLEAN and option "-k" (for kerneld"): Bjorn and Jacques
  35.  */
  36.  
  37. #ifndef MOD_AUTOCLEAN /* defined in <linux/module.h> by the "kerneld"-patch */
  38. #define MOD_AUTOCLEAN 0x40000000 /* big enough, but no sign problems... */
  39. #endif
  40.  
  41. static char *default_path[] = {
  42.     ".", "/linux/modules",
  43.     "/lib/modules/%s/fs",
  44.     "/lib/modules/%s/net",
  45.     "/lib/modules/%s/scsi",
  46.     "/lib/modules/%s/misc",
  47.     "/lib/modules/default/fs",
  48.     "/lib/modules/default/net",
  49.     "/lib/modules/default/scsi",
  50.     "/lib/modules/default/misc",
  51.     "/lib/modules/fs",
  52.     "/lib/modules/net",
  53.     "/lib/modules/scsi",
  54.     "/lib/modules/misc",
  55.     0
  56. };
  57.  
  58. #define PATCH_STRINGS
  59.  
  60. #include "insmod.h"
  61. #define is_global(sp) (aout_flag?(sp->u.n.n_type & N_EXT) : \
  62.                 (ELF32_ST_BIND(sp->u.e.st_info) == STB_GLOBAL))
  63. #define is_undef(sp) (aout_flag?((sp->u.n.n_type & ~N_EXT) == N_UNDF) : \
  64.                 (ELF32_ST_TYPE(sp->u.e.st_info) == STT_NOTYPE))
  65.  
  66. /* hack: sizeof(struct elfhdr) > sizeof(struct exec) */
  67. Elf32_Ehdr header;
  68. int aout_flag; /* to know the format of the module */
  69. int elf_kernel = 0; /* to know the format of the kernel */
  70.  
  71. size_t codesize;
  72. size_t progsize;
  73. size_t bss1size;
  74. size_t bss2size;
  75.  
  76. char *textseg;
  77.  
  78. int nsymbols;
  79. struct symbol *symtab;
  80. char *stringtab;
  81. unsigned long addr;
  82. int verbose = 0;
  83.  
  84. static int export_flag = 1; /* See comment att option handler in main() */
  85. static int force_load = 0;
  86. static int loadmap = 0;
  87. static int versioned_kernel = 0;
  88. static struct kernel_sym nullsym;
  89. static struct symbol *symroot;
  90. static struct utsname uts_info;
  91.  
  92. void *
  93. ckalloc(size_t nbytes)
  94. {
  95.     void *p;
  96.  
  97.     if ((p = malloc(nbytes)) == NULL) {
  98.             perror("insmod: malloc failed");
  99.         exit(2);
  100.     }
  101.     return p;
  102. }
  103.  
  104. void *
  105. ckrealloc(void *ptr, size_t nbytes)
  106. {
  107.         void *p;
  108.  
  109.     if ((p = realloc(ptr, nbytes)) == NULL) {
  110.             perror("insmod: realloc failed");
  111.         exit(2);
  112.     }
  113.     return p;
  114. }
  115.  
  116. static int create_module(const char *name, unsigned long size)
  117. {
  118.     return syscall( __NR_create_module, name, size);
  119. }
  120.  
  121. static int init_module(const char *name, void *code, unsigned codesize,
  122.         struct mod_routines *routines,
  123.         struct symbol_table *syms) {
  124.     return syscall( __NR_init_module, name, code, codesize, routines,
  125.         syms);
  126. }
  127.  
  128. static int delete_module(const char *name)
  129. {
  130.     return syscall( __NR_delete_module, name);
  131. }
  132.  
  133. static int get_kernel_syms(struct kernel_sym *buffer)
  134. {
  135.     return syscall( __NR_get_kernel_syms, buffer);
  136. }
  137.  
  138. void check_version(int force_load)
  139. {
  140.     unsigned long kernel_version;
  141.  
  142.     /* Check if module and kernel version match */
  143.     kernel_version = looksym("kernel_version");
  144.     if (strcmp( (char*) textseg + kernel_version, uts_info.release)) {
  145.         insmod_error (
  146.             "Error: The module was compiled on kernel version %s.\n"
  147.             "       This kernel is version %s. They don't match!\n"
  148.             "       Check that the module is usable with the current kernel,\n"
  149.             "       recompile the module and try again.",
  150.             (char*) textseg + kernel_version, uts_info.release);
  151.         if (force_load)
  152.             insmod_error("       Trying to load it anyway...");
  153.         else
  154.             exit( 2);
  155.     }
  156.  
  157. }
  158.  
  159. /*
  160.  * unversioned kernel, versioned module
  161.  */
  162. int
  163. m_strncmp(const char *tabentry, const char *lookfor, size_t n)
  164. {
  165.     int len = strlen(lookfor);
  166.     int retval;
  167.  
  168.     if ((retval = strncmp(tabentry, lookfor, len)) != 0)
  169.         return retval;
  170.     /* else */
  171.     if ((strncmp(tabentry + len, "_R", 2) == 0) &&
  172.         (strlen(tabentry + len) == 10))
  173.         return 0;
  174.     else
  175.         return retval;
  176. }
  177.  
  178. /*
  179.  * versioned kernel, unversioned module
  180.  */
  181. int
  182. k_strncmp(const char *tabentry, const char *lookfor, size_t n)
  183. {
  184.     int len = strlen(tabentry);
  185.     int retval;
  186.  
  187.     if ((retval = strncmp(tabentry, lookfor, len)) != 0)
  188.         return retval;
  189.     /* else */
  190.     if ((strncmp(lookfor + len, "_R", 2) == 0) &&
  191.         (strlen(lookfor + len) == 10))
  192.         return 0;
  193.     else
  194.         return retval;
  195. }
  196.  
  197. #ifdef PATCH_STRINGS
  198. struct strpatch {
  199.     int *where;
  200.     int what;
  201. };
  202. static struct strpatch *stringpatches;
  203. static int n_stringpatches;
  204.  
  205. static void
  206. push_string(char *string, int *patchme)
  207. {
  208.     int len;
  209.     unsigned int string_offset = progsize;
  210.     char *p;
  211.  
  212.     if ((p = strchr(string, ',')) != (char *)0)
  213.         len = p - string;
  214.     else
  215.         len = strlen(string);
  216.  
  217.     progsize += len + 1;
  218.     /* JEJB: don't like this, but if we're copying strings, better make
  219.      * sure memory actually exists to copy them into */
  220.     textseg = ckrealloc(textseg, progsize);
  221.     strncpy(textseg + string_offset, string, len);
  222.     *(textseg + string_offset + len) = '\0';
  223.  
  224.     if (n_stringpatches == 0)
  225.         stringpatches = (struct strpatch *)ckalloc(sizeof(struct strpatch));
  226.     else
  227.         stringpatches = (struct strpatch *)ckrealloc(stringpatches,
  228.             (n_stringpatches + 1) * sizeof(struct strpatch));
  229.  
  230.     (*(stringpatches + n_stringpatches)).where = patchme;
  231.     (*(stringpatches + n_stringpatches)).what = string_offset;
  232.     ++n_stringpatches;
  233. }
  234. #endif
  235.  
  236. int
  237. main(int argc, char **argv)
  238. {
  239.     FILE *fp;
  240.     struct exec *aouthdr = (struct exec *)&header;
  241.     struct kernel_sym *curr_module = &nullsym;
  242.     struct kernel_sym *ksymtab = NULL;
  243.     struct kernel_sym *ksym = NULL;
  244.     struct kernel_sym *resident_ksym_start = NULL;
  245.     struct mod_routines routines;
  246.     struct symbol *sp;
  247.     unsigned long init_func, cleanup_func;
  248.     int (*tabcomp) (const char *, const char *, size_t) = strncmp;
  249.     int fatal_error;
  250.     int i;
  251.     int nksyms;
  252.     int versioned_module;
  253.     int found_resident = -1;
  254.     int autoclean = 0; /* for insertions from kerneld: option "-k" */
  255.     int bss_offset;
  256.  
  257.     struct symbol_table *newtab;
  258.     int module_refs = 0; /* number of references modules */
  259.     int n_symboldefs = 0; /* number of defined symbols in the module */
  260.     int string_table_size = 0; /* size of the new symbol table string table */
  261.     struct internal_symbol *symp;
  262.     struct module_ref *refp;
  263.     char *stringp;
  264.  
  265.     char *filename;
  266.     char spare_path[200]; /* just testing... */
  267.     char *modname = NULL;
  268.     char *otextseg; /* JEJB: store the initial textseg, so we get offset */
  269.     char *p;
  270.  
  271.     /* find basename */
  272.     
  273.     if ((p = strrchr(argv[0], '/')) != (char *)0)
  274.         ++p;
  275.     else
  276.         p = argv[0];
  277.  
  278.     if (strcmp(p, "rmmod") == 0)
  279.         return rmmod(argc, argv);
  280.  
  281.     if (strcmp(p, "ksyms") == 0)
  282.         return ksyms(argc, argv);
  283.  
  284.     /* else  this is insmod! */
  285.  
  286.     while (argc > 1 && (argv[1][0] == '-')) {
  287.         p = &(argv[1][1]);
  288.         while (*p) {
  289.             switch (*p) {
  290.             case 'o':
  291.                 modname = argv[2];
  292.                 --argc;
  293.                 ++argv;
  294.                 break;
  295.  
  296.             case 'f': /* force loading */
  297.                 force_load = 1;
  298.                 break;
  299.  
  300.             case 'X': /* _do_ export externs */
  301.                 export_flag = 1;
  302.                 break;
  303.  
  304.             case 'x': /* do _not_ export externs */
  305.                 export_flag = 0;
  306.                 break;
  307.  
  308.             case 'm': /* generate loadmap */
  309.                 loadmap = 1;
  310.                 break;
  311.  
  312.             case 'k': /* module loaded by kerneld, auto-cleanable */
  313.                 autoclean = MOD_AUTOCLEAN;
  314.                 break;
  315.  
  316.             case 'v': /* verbose output */
  317.                 verbose = 1;
  318.                 break;
  319.             case 's':
  320.                 insmod_setsyslog("insmod");
  321.                 break;
  322.             }
  323.             ++p;
  324.         }
  325.         --argc;
  326.         ++argv;
  327.     }
  328.  
  329.     if (argc < 2) {
  330.         fputs("Usage: insmod [-f] [-x] [-o name] [-m] [-s] [-v] module "
  331.             "[[sym=value]...]\n", stderr);
  332.         exit(2);
  333.     }
  334.  
  335.     uname(&uts_info);
  336.  
  337.     filename = argv[1];
  338.     argv += 2;
  339.     --argc;
  340.  
  341.     /* get the size of the current kernel symbol table */
  342.     nksyms = get_kernel_syms(NULL);
  343.  
  344.     if (nksyms < 0) {
  345.         insmod_error("get_kernel_sys failed: Cannot find Kernel symbols!");
  346.         exit(2);
  347.     }
  348.  
  349.     if (nksyms) {
  350.         ksymtab = (struct kernel_sym *) ckalloc(nksyms * sizeof *ksymtab);
  351.         /* NOTE!!! The order of the symbols is important */
  352.         if (get_kernel_syms(ksymtab) != nksyms) {
  353.             insmod_error ("Kernel symbol problem");
  354.             exit(2);
  355.         }
  356.     }
  357.  
  358.     /* Is this a kernel with appended CRC-versions? */
  359.     for (ksym = ksymtab, i = 0 ; i < nksyms ; ++i, ksym++) {
  360.         if (found_resident == -1 && strcmp(ksym->name, "#") == 0) {
  361.             resident_ksym_start = ksym;
  362.             found_resident = i;
  363.             break;
  364.         }
  365.     }
  366.  
  367.     /* look only in residents */
  368.     if (found_resident != -1) {
  369.         ++ksym;
  370.         /* The first symbol in a versioned kernel is _Using_Versions */
  371.         if ((strcmp(ksym->name, "_Using_Versions") == 0) ||
  372.             (strcmp(ksym->name, "Using_Versions") == 0))
  373.                 versioned_kernel = 1;
  374.  
  375.         /* look at a "normal" symbol: */
  376.         ++ksym;
  377.         if (((i + 1) < nksyms) && (ksym->name[0] != '_'))
  378.             elf_kernel = 1;
  379.     }
  380.  
  381.     /* construct the module name */
  382.     if (modname == NULL) {
  383.         int len;
  384.  
  385.         if ((p = strrchr(filename, '/')) != NULL)
  386.             p++;
  387.         else
  388.             p = filename;
  389.         len = strlen(p);
  390.         if (len > 2 && strcmp(p + len - 2, ".o") == 0)
  391.             len -= 2;
  392.         else if (len > 4 && strcmp(p + len - 4, ".mod") == 0)
  393.             len -= 4;
  394.  
  395.         modname = (char*) ckalloc(len + 1);
  396.         memcpy(modname, p, len);
  397.         modname[len] = '\0';
  398.     }
  399.  
  400.     if ((strchr(filename, '/') == 0) && (strchr(filename, '.') == 0)) {
  401.         struct stat dummy;
  402.         char **defp;
  403.         char *path;
  404.         char *onepath;
  405.         char *p;
  406.  
  407.         /* Look in the path given by MODPATH environment,
  408.          * if not found, look in the default directories.
  409.                  * <storner@osiris.ping.dk> 950319 + Bjorn
  410.          */
  411.         if ((path = getenv("MODPATH")) == 0)  {
  412.             onepath = ckalloc(2000); /* or whatever */
  413.             onepath[0] = '\0';
  414.             for (defp = default_path; *defp; ++defp) {
  415.                 sprintf(spare_path, *defp, uts_info.release);
  416.                 strcat(onepath, spare_path);
  417.                 strcat(onepath, ":");
  418.             }
  419.         }
  420.         else {
  421.             onepath = ckalloc(strlen(path)+2);
  422.             sprintf(onepath, "%s:", path);
  423.         }
  424.  
  425.         for (path = onepath; (*path != '\0'); path += strlen(path)+1) {
  426.             for (p = path; (*p != ':') && (*p != '\0'); p++)
  427.                 ; 
  428.             *p = '\0';
  429.             sprintf(spare_path, "%s/%s", path, filename);
  430.             if (stat(spare_path, &dummy) >= 0) 
  431.                 break;
  432.             /* else */
  433.             strcat(spare_path, ".o");
  434.             if (stat(spare_path, &dummy) >= 0) 
  435.                 break;
  436.         }
  437.         free(onepath);
  438.         filename = spare_path;
  439.     }
  440.  
  441.     /* open file and read header */
  442.     if ((fp = fopen(filename, "r")) == NULL) {
  443.         insmod_error ("Cannot open %s", filename);
  444.         exit(2);
  445.     }
  446.  
  447.     /* sizeof(struct elfhdr) > sizeof(struct exec) */
  448.     fread(&header, sizeof(Elf32_Ehdr), 1, fp);
  449.     if (feof(fp) || ferror(fp)) {
  450.         insmod_error ("Could not read header of %s", filename);
  451.         exit(2);
  452.     }
  453.  
  454.     symtab = (struct symbol *)0;
  455.     nsymbols = 0;
  456.  
  457.     if (N_MAGIC((*aouthdr)) == OMAGIC) {
  458.         char *errstr;
  459.  
  460.         if ((errstr = load_aout(fp)) != (char *)0) {
  461.             insmod_error ("%s: %s", filename, errstr);
  462.             exit(2);
  463.         }
  464.     }
  465.     else if ((header.e_ident[0] == 0x7f) &&
  466.          (strncmp(&header.e_ident[1], "ELF",3) == 0) &&
  467.          (header.e_type == ET_REL) &&
  468.          ((header.e_machine == 3) || (header.e_machine == 6))
  469.         ) {
  470.             char *errstr;
  471.  
  472.             if ((errstr = load_elf(fp)) != (char *)0) {
  473.                 insmod_error ("%s: %s", filename, errstr);
  474.                 exit(2);
  475.             }
  476.     }
  477.     else {
  478.         insmod_error ("%s: not an object file", filename);
  479.         exit(2);
  480.     }
  481.  
  482.     /* JEJB: now we have textseg fixed after the load, so save value
  483.      * for later finding offset if realloc forces a move */
  484.     otextseg = textseg;
  485.  
  486.     if (findsym("Using_Versions", NULL, strncmp))
  487.         versioned_module = 1;
  488.     else
  489.         versioned_module = 0;
  490.  
  491.     /* check version info */
  492.         if (verbose) {
  493.         insmod_error ("versioned kernel: %s\nversioned module: %s",
  494.             versioned_kernel ? "yes" : "no",
  495.             versioned_module ? "yes" : "no");
  496.         insmod_error ("%s kernel\n%s module",
  497.             elf_kernel ? "ELF" : "a.out",
  498.             aout_flag ? "a.out" : "ELF");
  499.     }
  500.     /*
  501.      * Logic:
  502.      *
  503.      * versioned_kernel versioned_module    action
  504.      * ================ ================    =============================
  505.      *    no        no        same kernel and module version
  506.      *                    all symbols must match
  507.      *    no        yes        same kernel and module version
  508.      *                    ignore symbol version suffix
  509.      *    yes        no        same kernel and module version
  510.      *                    ignore symbol version suffix
  511.      *    yes        yes        all symbols must match,
  512.      *                    including the version suffix
  513.      */
  514.     switch ((versioned_kernel << 1) + versioned_module) {
  515.     case 0: /* unversioned_kernel, unversioned_module */
  516.         check_version(force_load);
  517.         tabcomp = strncmp;
  518.         break;
  519.  
  520.     case 1: /* unversioned_kernel, versioned_module */
  521.         check_version(force_load);
  522.         tabcomp = m_strncmp;
  523.         break;
  524.  
  525.     case 2: /* versioned_kernel,   unversioned_module */
  526.         check_version(force_load);
  527.         tabcomp = k_strncmp;
  528.         break;
  529.  
  530.     case 3: /* versioned_kernel,   versioned_module */
  531.         tabcomp = strncmp;
  532.         break;
  533.  
  534.     }
  535.  
  536.     /* get initialization and cleanup routines */
  537.     init_func = looksym("init_module");
  538.     cleanup_func = looksym("cleanup_module");
  539.  
  540.     /* bind undefined symbols (ELF-stuff hidden in defsym()) */
  541.     defsym(strncmp, "mod_use_count_", 0 - sizeof (int), N_BSS | N_EXT, TRANSIENT);
  542.  
  543.     /* First: resolve symbols using kernel transient symbols */
  544.     /* Then: use resident kernel symbols to resolve the last ones... */
  545.     for (ksym = ksymtab, i = 0 ; i < nksyms ; ++i, ksym++) {
  546.         /* Magic in this version of the new get_kernel_syms:
  547.          * Every module is sent along as a symbol,
  548.          * where the module name is represented as "#module", and
  549.          * the address of the module struct is stuffed into the value.
  550.          * The name "#" means that the symbols that follow are
  551.          * kernel resident.
  552.          */
  553.         if (ksym->name[0] == '#') {
  554.             curr_module = ksym;
  555.             continue;
  556.         }
  557.  
  558.         if (defsym(tabcomp, ksym->name + (elf_kernel?0:1),
  559.             ksym->value, N_ABS | N_EXT,
  560.         /* this is safe since curr_module was initialized properly */
  561.             (curr_module->name[1]) ?  TRANSIENT : RESIDENT)) {
  562.             /* kludge: mark referenced modules */
  563.             if (curr_module->name[1] && /* but not the kernel */
  564.                 (curr_module->name[0] == '#')) {
  565.                 curr_module->name[0] = '+';
  566.                 ++module_refs;
  567.             }
  568.         }
  569.     }
  570.  
  571.     /* allocate space for "common" symbols */
  572.     /* and check for undefined symbols */
  573.     fatal_error = 0;
  574.     bss_offset = codesize + bss1size;
  575.     /*
  576.      * Scan symbol table to determine global bss size
  577.      */
  578.     for (sp = symtab ; sp < symtab + nsymbols ; sp++) {
  579.         if ((symname(sp) == (char *)0) || (*symname(sp) == '\0'))
  580.             continue;
  581.  
  582.         if ( ((aout_flag && (sp->u.n.n_type == (N_UNDF | N_EXT))) ||
  583.             (!aout_flag && is_global(sp) && is_undef(sp)))
  584.             && (symvalue(sp) != 0)) {
  585.             int len;
  586.  
  587.             if (aout_flag) {
  588.                 sp->u.n.n_type = N_BSS | N_EXT;
  589.                 len = symvalue(sp);
  590.                  if (verbose)
  591.                          insmod_error (
  592.                      "bss2 sym %08x, size =%7d: %s",
  593.                              bss_offset, len, symname( sp));
  594.             }
  595.             else { /* I'm not sure I understand this... */
  596.                 sp->u.e.st_info = (STB_GLOBAL << 4)| STT_OBJECT;
  597.                 len = (sp->u.e.st_size)?(sp->u.e.st_size):4;
  598.             }
  599.              symvalue(sp) = bss_offset;
  600.              bss_offset += len;
  601.         } else if (is_undef(sp)) {
  602.             if (versioned_module) {
  603.                 char *v = strrchr(symname(sp), '_');
  604.                 if (v && (strncmp(v, "_R", 2) == 0) &&
  605.                     (strlen(v) == 10))
  606.                     *v = '\0';
  607.                 insmod_error ("%s: wrong version",
  608.                     symname(sp));
  609.                 if (v && !(*v))
  610.                     *v = '_';
  611.             }
  612.             else
  613.                 insmod_error ("%s undefined", symname(sp));
  614.             fatal_error = 1;
  615.         }
  616.     }
  617.     if (fatal_error) {
  618.         insmod_error ("Failed to load module! The symbols from kernel %s don't match %s",
  619.             (char*) textseg + looksym("kernel_version"),
  620.             uts_info.release);
  621.         exit(2);
  622.     }
  623.  
  624.     /* Change values according to the parameters to "insmod" */
  625.     {
  626.         struct symbol *change;
  627.         int *patchme;
  628.         char *param;
  629.         char *val;
  630.         int value;
  631.  
  632.         while (argc > 1) {
  633.             param = *argv;
  634.             ++argv;
  635.             --argc;
  636.  
  637.             /*
  638.              * This makes the following contruct legal:
  639.              *    insmod module.o -o new_name
  640.              * This is used by the "options" configuration
  641.              * lines for modprobe.
  642.              */
  643.             if (strcmp(param, "-o") == 0) {
  644.                 modname = (char*) ckalloc(strlen(argv[0]) + 1);
  645.                 strcpy(modname, argv[0]);
  646.                 --argc;
  647.                 ++argv;
  648.                 continue;
  649.             }
  650.             if ((val = strchr(param, '=')) == NULL)
  651.                 continue;
  652.             *val = '\0'; /* mark end of tag */
  653.  
  654.             if (versioned_module)
  655.                 change = findsym(param, NULL, m_strncmp);
  656.             else
  657.                 change = findsym(param, NULL, strncmp);
  658.             if (change == NULL) {
  659.                 insmod_error ("Symbol '%s' not found", param);
  660.                 exit(2);
  661.             }
  662.             patchme = (int *)(textseg + symvalue(change));
  663.  
  664.             do {
  665.                 ++val;
  666.                 if (*val < '0' || '9' < *val) {
  667. #ifdef PATCH_STRINGS
  668.                     if (*val != ',')
  669.                         push_string(val, patchme);
  670. #else
  671.                     insmod_error ("Symbol '%s' has an illegal value: %s", param, val);
  672.                     exit(2);
  673. #endif
  674.                 }
  675.                 else { /* numerical */
  676.                     if (val[0] == '0') {
  677.                         if (val[1] == 'x')
  678.                             sscanf(val, "%x", &value);
  679.                         else
  680.                             sscanf(val, "%o", &value);
  681.                     }
  682.                     else
  683.                         sscanf(val, "%d", &value);
  684.                     *patchme = value;
  685.                 }
  686.                 ++patchme;
  687.             } while ((val = strchr(val, ',')) != (char *)0);
  688.         }
  689.     }
  690.  
  691.     /* create the module */
  692.     errno = 0;
  693.     /* make sure we have enough memory malloc'd for copy which kernel
  694.      * will perform */
  695.     textseg = ckrealloc(textseg, progsize);
  696.     /* We add "sizeof (int)" to skip over the use count */
  697.     addr = create_module(modname, progsize) + sizeof (int);
  698.  
  699.     switch (errno) {
  700.     case EEXIST:
  701.         insmod_error ("A module named %s already exists", modname);
  702.         exit(2);
  703.     case ENOMEM:
  704.         insmod_error ("Cannot allocate space for module");
  705.         exit(2);
  706.     case 0:
  707.         break;
  708.     default:
  709.         perror("create_module");
  710.         exit(2);
  711.     }
  712.  
  713.     /* perform relocation */
  714.     if (aout_flag)
  715.         relocate_aout(fp, textseg - otextseg);
  716.     else
  717.         relocate_elf(fp, textseg - otextseg);
  718.  
  719. #ifdef PATCH_STRINGS
  720.     {
  721.         struct strpatch *p = stringpatches;
  722.  
  723.         while (--n_stringpatches >= 0) {
  724.             *(p->where) = (int)addr + p->what;
  725.             ++p;
  726.         }
  727.  
  728.         free(stringpatches);
  729.         n_stringpatches = 0;
  730.     }
  731. #endif
  732.     init_func += addr;
  733.     cleanup_func += addr;
  734.  
  735.     /* "hide" the module specific symbols, not to be exported! */
  736.     hidesym("cleanup_module");
  737.     hidesym("init_module");
  738.     hidesym("kernel_version");
  739.     hidesym("mod_use_count_");
  740.  
  741.     /* Build the module symbol table */
  742.     /* abuse of *_other:
  743.      * 0    refer kernel resident
  744.      * 1    define module symbol, inserted in kernel syms
  745.      * 2    refer module symbol
  746.      * 3    won't happen (define resolved by other module?)
  747.      */
  748.  
  749.     /*
  750.      * Get size info for the new symbol table
  751.      * we already have module_refs
  752.      */
  753.     for (sp = symtab ; export_flag && (sp < symtab + nsymbols) ; sp++) {
  754.         if (is_global(sp) && (symother(sp) & DEF_BY_MODULE)) {
  755.             string_table_size += strlen(symname(sp)) + 1;
  756.             if (!elf_kernel)
  757.                 ++string_table_size;
  758.             ++n_symboldefs;
  759.         }
  760.     }
  761.     newtab = (struct symbol_table *)ckalloc(sizeof(struct symbol_table) +
  762.         n_symboldefs * sizeof(struct internal_symbol) +
  763.         module_refs * sizeof(struct module_ref) +
  764.         string_table_size);
  765.  
  766.     newtab->size = sizeof(struct symbol_table) +
  767.         n_symboldefs * sizeof(struct internal_symbol) +
  768.         module_refs * sizeof(struct module_ref) +
  769.         string_table_size;
  770.  
  771.     newtab->n_symbols = n_symboldefs;
  772.     newtab->n_refs = module_refs;
  773.  
  774.     symp = &(newtab->symbol[0]);
  775.     stringp = ((char *)symp) + 
  776.         n_symboldefs * sizeof(struct internal_symbol) +
  777.         module_refs * sizeof(struct module_ref);
  778.  
  779.     /* update the string pointer (to a string index) in the symbol table */
  780.     for (sp = symtab ; export_flag && (sp < symtab + nsymbols) ; sp++) {
  781.         if (is_global(sp) && (symother(sp) & DEF_BY_MODULE)) {
  782.             symp->addr = (void *)(symvalue(sp) + addr);
  783.             symp->name = (char *)(stringp - (char *)newtab);
  784.             if (!elf_kernel) {
  785.                 strcpy(stringp, "_");
  786.                 ++stringp;
  787.             }
  788.             strcpy(stringp, symname(sp));
  789.             stringp += strlen(symname(sp)) + 1;
  790.             ++symp;
  791.         }
  792.     }
  793.  
  794.     refp = (struct module_ref *)symp;
  795.     for (ksym = ksymtab, i = 0 ; i < nksyms ; ++i, ksym++) {
  796.         if (ksym->name[0] == '+') {
  797.             refp->module = (struct module *)ksym->value;
  798.             ++refp;
  799.         }
  800.     }
  801.  
  802.     /* load the module into the kernel */
  803.     /* NOTE: the symbol table == NULL if there are no defines/updates */
  804.     routines.init = (int (*)(void)) init_func;
  805.     routines.cleanup = (void (*)(void)) cleanup_func;
  806.  
  807.     if (init_module(modname, textseg,
  808.         /* An autoclean marker for a non-kerneld-aware kernel
  809.          * will result in a rejection of the module.
  810.          * This is what we want, since the "-k" option is useful
  811.          * only with kerneld aware kernels...
  812.          */
  813.         autoclean | progsize /*codesize*/, &routines,
  814.         ((n_symboldefs + module_refs)? newtab : NULL)) < 0) {
  815.  
  816.         if (errno == EBUSY) {
  817.             insmod_error ("Initialization of %s failed", modname);
  818.         } else {
  819.             perror("init_module");
  820.         }
  821.         delete_module(modname);
  822.         exit(1);
  823.     }
  824. #ifdef DEBUG_DISASM
  825. dis(textseg, codesize);
  826. #endif
  827.     /*
  828.      * Print a loadmap so that kernel panics can be identified.
  829.      * Load map option conceived by Derek Atkins <warlord@MIT.EDU>
  830.      */
  831.     for (sp = symtab; loadmap && (sp < symtab + nsymbols) ; sp++) {
  832.         char symtype = 'u';
  833.  
  834.         if (aout_flag) {
  835.             if ((sp->u.n.n_type & ~N_EXT) == N_ABS)
  836.                 continue;
  837.  
  838.             switch (sp->u.n.n_type & ~N_EXT) {
  839.             case N_TEXT | N_EXT: symtype = 'T'; break;
  840.             case N_TEXT: symtype = 't'; break;
  841.             case N_DATA | N_EXT: symtype = 'D'; break;
  842.             case N_DATA: symtype = 'd'; break;
  843.             case N_BSS | N_EXT: symtype = 'B'; break;
  844.             case N_BSS: symtype = 'b'; break;
  845.             }
  846.         }
  847.         else
  848.             symtype = ' '; /* until someone does the work... */
  849.  
  850.         printf("%08lx %c %s\n",
  851.             symvalue(sp) + addr, symtype, symname(sp));
  852.     }
  853.  
  854.     if (nksyms > 0)
  855.         free(ksymtab); /* it has done its job */
  856.  
  857.     exit(0);
  858. }
  859.  
  860. void
  861. hidesym(const char *name)
  862. {
  863.     struct symbol *sp;
  864.  
  865.     if ((sp = findsym(name, NULL, strncmp)) != NULL) {
  866.         if (aout_flag)
  867.             sp->u.n.n_type &= ~N_EXT;
  868.         else
  869.             sp->u.e.st_info = (STB_LOCAL << 4) |
  870.                           (ELF32_ST_TYPE(sp->u.e.st_info));
  871.     }
  872. }
  873.  
  874. int
  875. defsym(int (*pfi) (const char *, const char *, size_t),
  876.     const char *name, unsigned long value, int type, int source)
  877. {
  878.     struct symbol *sp;
  879.     /*
  880.      * field "*_other" abused in the symbol table
  881.      * in order to discriminate between defines and references
  882.      * and resolves by kernel resident or transient symbols...
  883.      */
  884.  
  885.     if ((sp = findsym(name, NULL, pfi)) == NULL)
  886.         return 0; /* symbol not used */
  887.     /* else */
  888.  
  889.     /*
  890.      * Multiply defined?
  891.      * Well, this is what we _want_!
  892.      * I.e. a module _should_ be able to replace a kernel resident
  893.      * symbol, or even a symbol defined by another module!
  894.      * NOTE: The symbols read from the kernel (the transient ones)
  895.      * MUST be handled in the order:
  896.      *   last defined, ..., earlier defined, ...
  897.      */
  898.     if (aout_flag) {
  899.         if (sp->u.n.n_type != (N_UNDF | N_EXT))
  900.             return 0; /* symbol not used */
  901.         sp->u.n.n_type = type;
  902.     }
  903.     else { /* elf */
  904.         if ((ELF32_ST_BIND(sp->u.e.st_info) != STB_GLOBAL) ||
  905.             (ELF32_ST_TYPE(sp->u.e.st_info) != STT_NOTYPE))
  906.             return 0; /* symbol not used */
  907.         /* hack follows... */
  908.         if (type & N_ABS)
  909.             sp->u.e.st_info = (STB_GLOBAL << 4);
  910.         else
  911.             sp->u.e.st_info = (STB_LOCAL << 4);
  912.         sp->u.e.st_info |= STT_OBJECT; /* or whatever */
  913.     }
  914.  
  915.     symother(sp) |= source;
  916.     symvalue(sp) = value;
  917.  
  918.     return 1; /* symbol used */
  919. }
  920.  
  921.  
  922. /*
  923.  * Look up an name in the symbol table.  If "add" is not null, add a
  924.  * the entry to the table.  The table is stored as a splay tree.
  925.  */
  926. struct symbol *
  927. findsym(const char *key, struct symbol *add,
  928.     int (*pfi) (const char *, const char *, size_t))
  929. {
  930.     struct symbol *left, *right;
  931.     struct symbol **leftp, **rightp;
  932.     struct symbol *sp1, *sp2, *sp3;
  933.     int cmp;
  934.     int path1, path2;
  935.  
  936.     if (add) {
  937.         if (aout_flag)
  938.             add->u.n.n_un.n_name = (char *)key;
  939.         else
  940.             add->u.e.st_name = (Elf32_Word)key;
  941.     }
  942.     sp1 = symroot;
  943.     if (sp1 == NULL)
  944.         return add? symroot = add : NULL;
  945.     leftp = &left, rightp = &right;
  946.     for (;;) {
  947.         cmp = (*pfi)(symname(sp1), key, SYM_MAX_NAME);
  948.         if (cmp == 0)
  949.             break;
  950.         if (cmp > 0) {
  951.             sp2 = sp1->child[0];
  952.             path1 = 0;
  953.         } else {
  954.             sp2 = sp1->child[1];
  955.             path1 = 1;
  956.         }
  957.         if (sp2 == NULL) {
  958.             if (! add)
  959.                 break;
  960.             sp2 = add;
  961.         }
  962.         cmp = (*pfi)(symname(sp2), key, SYM_MAX_NAME);
  963.         if (cmp == 0) {
  964. one_level_only:
  965.             if (path1 == 0) {    /* sp2 is left child of sp1 */
  966.                 *rightp = sp1;
  967.                 rightp = &sp1->child[0];
  968.             } else {
  969.                 *leftp = sp1;
  970.                 leftp = &sp1->child[1];
  971.             }
  972.             sp1 = sp2;
  973.             break;
  974.         }
  975.         if (cmp > 0) {
  976.             sp3 = sp2->child[0];
  977.             path2 = 0;
  978.         } else {
  979.             sp3 = sp2->child[1];
  980.             path2 = 1;
  981.         }
  982.         if (sp3 == NULL) {
  983.             if (! add)
  984.                 goto one_level_only;
  985.             sp3 = add;
  986.         }
  987.         if (path1 == 0) {
  988.             if (path2 == 0) {
  989.                 sp1->child[0] = sp2->child[1];
  990.                 sp2->child[1] = sp1;
  991.                 *rightp = sp2;
  992.                 rightp = &sp2->child[0];
  993.             } else {
  994.                 *rightp = sp1;
  995.                 rightp = &sp1->child[0];
  996.                 *leftp = sp2;
  997.                 leftp = &sp2->child[1];
  998.             }
  999.         } else {
  1000.             if (path2 == 0) {
  1001.                 *leftp = sp1;
  1002.                 leftp = &sp1->child[1];
  1003.                 *rightp = sp2;
  1004.                 rightp = &sp2->child[0];
  1005.             } else {
  1006.                 sp1->child[1] = sp2->child[0];
  1007.                 sp2->child[0] = sp1;
  1008.                 *leftp = sp2;
  1009.                 leftp = &sp2->child[1];
  1010.             }
  1011.         }
  1012.         sp1 = sp3;
  1013.     }
  1014.     /*
  1015.      * Now sp1 points to the result of the search.  If cmp is zero,
  1016.      * we had a match; otherwise not.
  1017.      */
  1018.     *leftp = sp1->child[0];
  1019.     *rightp = sp1->child[1];
  1020.     sp1->child[0] = left;
  1021.     sp1->child[1] = right;
  1022.     symroot = sp1;
  1023.     return cmp == 0? sp1 : NULL;
  1024. }
  1025.  
  1026.  
  1027. unsigned long
  1028. looksym(const char *name)
  1029. {
  1030.     struct symbol *sp;
  1031.  
  1032.     sp = findsym(name, NULL, strncmp);
  1033.     if (sp == NULL) {
  1034.         insmod_error ("%s needed, but can't be found", name);
  1035.         exit(2);
  1036.     }
  1037.     return symvalue(sp);
  1038. }
  1039.  
  1040. /*
  1041.  * This is (was) rmmod, now merged with insmod!
  1042.  *
  1043.  * Original author: Jon Tombs <jon@gtex02.us.es>,
  1044.  * and extended by Bjorn Ekwall <bj0rn@blox.se> in 1994 (C).
  1045.  * See the file COPYING for your rights (GNU GPL)
  1046.  */
  1047.  
  1048. #define WANT_TO_REMOVE 1
  1049. #define CAN_REMOVE 2
  1050.  
  1051. struct ref {
  1052.     int modnum;
  1053.     struct ref *next;
  1054. };
  1055.  
  1056. struct mod {
  1057.     int status; /* or of: WANT_TO_REMOVE, CAN_REMOVE */
  1058.     char name[MOD_MAX_NAME];
  1059.     struct ref *ref;
  1060. };
  1061.  
  1062. struct mod *loaded;
  1063. int current = -1;
  1064.  
  1065. /* build the references as shown in /proc/ksyms */
  1066. void
  1067. get_stacks()
  1068. {
  1069.     FILE *fp;
  1070.     struct ref *rp;
  1071.     int i;
  1072.     char line[200]; /* or whatever... */
  1073.     char *p;
  1074.     char *r;
  1075.  
  1076.     if ((fp = fopen("/proc/modules", "r")) == (FILE *)0) {
  1077.         perror("/proc/modules");
  1078.         exit(1);
  1079.     }
  1080.  
  1081.     while (fgets(line, 200, fp)) {
  1082.         if (loaded) {
  1083.             ++current;
  1084.             loaded = (struct mod *)ckrealloc(loaded,
  1085.                 (current + 1) * sizeof(struct mod));
  1086.         } else {
  1087.             current = 0;
  1088.             loaded = (struct mod *)ckalloc(sizeof(struct mod));
  1089.         }
  1090.  
  1091.         loaded[current].status = 0;
  1092.         loaded[current].ref = (struct ref *)0;
  1093.  
  1094.         /* save the module name */
  1095.         p = strchr(line, ' ');
  1096.         *p = '\0';
  1097.         strcpy(loaded[current].name, line);
  1098.  
  1099.         /* any references? */
  1100.         if ((p = strchr(p + 1, '['))) {
  1101.             *(strrchr(p + 1, ']')) = '\0';
  1102.             do {
  1103.                 r = p + 1;
  1104.                 if ((p = strchr(r, ' ')))
  1105.                     *p = '\0';
  1106.                 for (i = 0; i < current; ++i) {
  1107.                     if (strcmp(loaded[i].name, r) == 0)
  1108.                         break;
  1109.                 }
  1110.  
  1111.                 if (i == current) { /* not found! */
  1112.                     insmod_error (
  1113.                     "Strange reference in "
  1114.                     "/proc/modules: '%s' used by '%s'?",
  1115.                     loaded[current].name, r);
  1116.                     exit(1);
  1117.                 }
  1118.  
  1119.                 rp = (struct ref *)ckalloc(sizeof(struct ref));
  1120.                 rp->modnum = i;
  1121.                 rp->next = loaded[current].ref;
  1122.                 loaded[current].ref = rp;
  1123.             } while (p);
  1124.         }
  1125.     }
  1126.  
  1127.     fclose(fp);
  1128. }
  1129.  
  1130. int
  1131. rmmod(int argc, char **argv)
  1132. {
  1133.     struct ref *rp;
  1134.     int i, j;
  1135.     int count;
  1136.     char **list;
  1137.     char *p;
  1138.  
  1139.     if (argc == 1) {
  1140.         fprintf(stderr, "usage: rmmod [-r] [-s] module ...\n");
  1141.         exit(1);
  1142.     }
  1143.     /* else */
  1144.  
  1145.     if (strcmp(argv[1], "-r") != 0) {
  1146.         if (strcmp(argv[1], "-a") == 0) {
  1147.             /* delete all unused modules and stacks */
  1148.             delete_module(NULL);
  1149.             exit(0);
  1150.         }
  1151.         /* else */
  1152.         if (strcmp(argv[1],"-s")==0){
  1153.             insmod_setsyslog("rmmod");
  1154.             --argc;
  1155.             ++argv;
  1156.         }
  1157.         while (argc > 1) {
  1158.             if ((p = strrchr(argv[1], '.')) &&
  1159.                 ((strcmp(p, ".o") == 0) ||
  1160.                  (strcmp(p, ".mod") == 0))) 
  1161.                     *p = '\0';
  1162.             if (delete_module(argv[1]) < 0) {
  1163.                 perror(argv[1]);
  1164.             }
  1165.             --argc;
  1166.             ++argv;
  1167.         }
  1168.         exit(0);
  1169.     }
  1170.     /* else recursive removal */
  1171.  
  1172.     count = argc - 2;
  1173.     list = &(argv[2]);
  1174.     if (count <= 0) {
  1175.         insmod_error ("usage: rmmod [-r] module ...");
  1176.         exit(1);
  1177.     }
  1178.  
  1179.     get_stacks();
  1180.  
  1181.     for (i = 0; i < count; ++i) {
  1182.         for (j = 0; j <= current; ++j) {
  1183.             if (strcmp(loaded[j].name, list[i]) == 0) {
  1184.                 loaded[j].status = WANT_TO_REMOVE;
  1185.                 break;
  1186.             }
  1187.         }
  1188.         if (j > current)
  1189.             insmod_error ("module '%s' not loaded", list[i]);
  1190.     }
  1191.  
  1192.     for (i = 0; i <= current; ++i) {
  1193.         if (loaded[i].ref || (loaded[i].status == WANT_TO_REMOVE))
  1194.             loaded[i].status |= CAN_REMOVE;
  1195.  
  1196.         for (rp = loaded[i].ref; rp; rp = rp->next) {
  1197.             switch (loaded[rp->modnum].status) {
  1198.             case CAN_REMOVE:
  1199.             case WANT_TO_REMOVE | CAN_REMOVE:
  1200.                 break;
  1201.  
  1202.             case WANT_TO_REMOVE:
  1203.                 if (loaded[rp->modnum].ref == (struct ref *)0)
  1204.                     break;
  1205.                 /* else fallthtough */
  1206.             default:
  1207.                 loaded[i].status &= ~CAN_REMOVE;
  1208.                 break;
  1209.             }
  1210.         }
  1211.  
  1212.         switch (loaded[i].status) {
  1213.         case CAN_REMOVE:
  1214.         case WANT_TO_REMOVE | CAN_REMOVE:
  1215.             if (delete_module(loaded[i].name) < 0) {
  1216.                 perror(loaded[i].name);
  1217.             }
  1218.             break;
  1219.  
  1220.         case WANT_TO_REMOVE:
  1221.             insmod_error ("module '%s' is in use!",
  1222.                 loaded[i].name);
  1223.             break;
  1224.         }
  1225.     }
  1226.  
  1227.     return 0;
  1228. }
  1229.  
  1230.  
  1231. /*
  1232.  * Used to be ksyms.c, but merged as well...
  1233.  *
  1234.  * Get kernel symbol table(s).
  1235.  *
  1236.  * Bjorn Ekwall <bj0rn@blox.se> in 1994 (C)
  1237.  * See the file COPYING for your rights (GNU GPL)
  1238.  */
  1239.  
  1240. int
  1241. ksyms(int argc, char **argv)
  1242. {
  1243.     struct kernel_sym *ksymtab = NULL;
  1244.     struct kernel_sym *ksym = NULL;
  1245.     struct module module_struct;
  1246.     int nksyms;
  1247.     int i;
  1248.     int kmem = 0;
  1249.     int allsyms = 0;
  1250.     int show_header = 1;
  1251.     char *p;
  1252.     char *module_name = "";
  1253.  
  1254.     while (argc > 1 && (argv[1][0] == '-')) {
  1255.         p = &(argv[1][1]);
  1256.         while (*p) {
  1257.             switch (*p) {
  1258.             case 'a':
  1259.                 allsyms = 1;
  1260.                 break;
  1261.  
  1262.             case 'm':
  1263.                 if ((kmem = open("/dev/kmem", O_RDONLY)) < 0) {
  1264.                     perror("/dev/kmem");
  1265.                     exit(2);
  1266.                 }
  1267.                 break;
  1268.  
  1269.             case 'h':
  1270.                 show_header = 0;
  1271.                 break;
  1272.             }
  1273.             ++p;
  1274.         }
  1275.         --argc;
  1276.         ++argv;
  1277.     }
  1278.  
  1279.     if (argc < 1) {
  1280.         fputs("Usage: ksyms [-a] [-h]\n", stderr);
  1281.         exit(2);
  1282.     }
  1283.  
  1284.     /* get the size of the current kernel symbol table */
  1285.     nksyms = get_kernel_syms(NULL);
  1286.  
  1287.     if (nksyms < 0) {
  1288.         insmod_error ("get_kernel_sys failed: Cannot find Kernel symbols!");
  1289.         exit(2);
  1290.     }
  1291.  
  1292.     if (nksyms) {
  1293.         ksymtab = (struct kernel_sym *) ckalloc(nksyms * sizeof *ksymtab);
  1294.         /* NOTE!!! The order of the symbols is important */
  1295.         if (get_kernel_syms(ksymtab) != nksyms) {
  1296.             insmod_error ("Kernel symbol problem");
  1297.             exit(2);
  1298.         }
  1299.     }
  1300.  
  1301.     if (show_header)
  1302.         printf("Address  Symbol    \tDefined by\n");
  1303.  
  1304.     for (ksym = ksymtab, i = 0 ; i < nksyms ; ++i, ksym++) {
  1305.         /* Magic in this version of the new get_kernel_syms:
  1306.          * Every module is sent along as a symbol,
  1307.          * where the module name is represented as "#module", and
  1308.          * the address of the module struct is stuffed into the value.
  1309.          * The name "#" means that the symbols that follow are
  1310.          * kernel resident.
  1311.          */
  1312.         if (ksym->name[0] == '#') {
  1313.             module_name = ksym->name + 1;
  1314.             if (!allsyms && (*module_name == '\0'))
  1315.                 break;
  1316.             /* else */
  1317.             if (kmem) {
  1318.                 if (
  1319.         (lseek(kmem, (off_t)ksym->value, SEEK_SET) > 0) &&
  1320.         (read(kmem, (char *)&module_struct, sizeof(struct module)) ==
  1321.         sizeof(struct module))) {
  1322.                     printf("%08lx --- (%dk) ---\t[%s]\n",
  1323.                     (long)module_struct.addr,
  1324.                     module_struct.size * 4,
  1325.                     module_name);
  1326.                 }
  1327.                 else {
  1328.                     perror("/dev/kmem");
  1329.                     exit(2);
  1330.                 }
  1331.             }
  1332.             continue;
  1333.         }
  1334.  
  1335.         printf("%08lx %s", ksym->value, ksym->name);
  1336.         if (*module_name)
  1337.             printf("\t[%s]", module_name);
  1338.         printf("\n");
  1339.     }
  1340.  
  1341.     return 0;
  1342. }
  1343.