home *** CD-ROM | disk | FTP | other *** search
/ PC Plus SuperCD (UK) 1999 May / pcp151c.iso / misc / src / install / modutils / genksyms / genksyms.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-01-06  |  11.7 KB  |  579 lines

  1. /* Generate kernel symbol version hashes.
  2.    Copyright 1996, 1997 Linux International.
  3.  
  4.    New implementation contributed by Richard Henderson <rth@tamu.edu>
  5.    Based on original work by Bjorn Eckwall <bj0rn@blox.se>
  6.  
  7.    This file is part of the Linux modutils.
  8.  
  9.    This program is free software; you can redistribute it and/or modify it
  10.    under the terms of the GNU General Public License as published by the
  11.    Free Software Foundation; either version 2 of the License, or (at your
  12.    option) any later version.
  13.  
  14.    This program is distributed in the hope that it will be useful, but
  15.    WITHOUT ANY WARRANTY; without even the implied warranty of
  16.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  17.    General Public License for more details.
  18.  
  19.    You should have received a copy of the GNU General Public License
  20.    along with this program; if not, write to the Free Software Foundation,
  21.    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
  22.  
  23. #ident "$Id: genksyms.c,v 1.1.1.1 1998/01/06 20:51:07 ewt Exp $"
  24.  
  25. #include <stdio.h>
  26. #include <string.h>
  27. #include <stdlib.h>
  28. #include <unistd.h>
  29. #include <assert.h>
  30. #include <stdarg.h>
  31.  
  32. #include "genksyms.h"
  33. #include "util.h"
  34. #include "version.h"
  35.  
  36. /*----------------------------------------------------------------------*/
  37.  
  38. #define HASH_BUCKETS  4099
  39.  
  40. static struct symbol *symtab[HASH_BUCKETS];
  41. FILE *outfile, *debugfile;
  42.  
  43. int cur_line = 1;
  44. char *cur_filename, *output_directory;
  45.  
  46. int flag_debug, flag_dump_defs, flag_export_globals, flag_warnings;
  47. int checksum_version = 1, kernel_version = version(2,0,0);
  48.  
  49. static int errors;
  50. static int nsyms;
  51.  
  52. static struct symbol *expansion_trail;
  53. static const char *crc_prefix = "";
  54.  
  55. static const char * const symbol_type_name[] = {
  56.   "normal", "typedef", "enum", "struct", "union"
  57. };
  58.  
  59. /*----------------------------------------------------------------------*/
  60.  
  61. static const unsigned int crctab32[] =
  62. {
  63. #include "crc32.tab"
  64. };
  65.  
  66. static inline unsigned long
  67. partial_crc32_one(unsigned char c, unsigned long crc)
  68. {
  69.   return crctab32[(crc ^ c) & 0xff] ^ (crc >> 8);
  70. }
  71.  
  72. static inline unsigned long
  73. partial_crc32(const char *s, unsigned long crc)
  74. {
  75.   while (*s)
  76.     crc = partial_crc32_one(*s++, crc);
  77.   return crc;
  78. }
  79.  
  80. static inline unsigned long
  81. crc32(const char *s)
  82. {
  83.   return partial_crc32(s, 0xffffffff) ^ 0xffffffff;
  84. }
  85.  
  86.  
  87. /*----------------------------------------------------------------------*/
  88.  
  89. static inline enum symbol_type
  90. map_to_ns(enum symbol_type t)
  91. {
  92.   if (t == SYM_TYPEDEF)
  93.     t = SYM_NORMAL;
  94.   else if (t == SYM_UNION)
  95.     t = SYM_STRUCT;
  96.   return t;
  97. }
  98.  
  99. struct symbol *
  100. find_symbol(const char *name, enum symbol_type ns)
  101. {
  102.   unsigned long h = crc32(name) % HASH_BUCKETS;
  103.   struct symbol *sym;
  104.  
  105.   for (sym = symtab[h]; sym ; sym = sym->hash_next)
  106.     if (map_to_ns(sym->type) == map_to_ns(ns) && strcmp(name, sym->name) == 0)
  107.       break;
  108.  
  109.   return sym;
  110. }
  111.  
  112. struct symbol *
  113. add_symbol(const char *name, enum symbol_type type, struct string_list *defn)
  114. {
  115.   unsigned long h = crc32(name) % HASH_BUCKETS;
  116.   struct symbol *sym;
  117.  
  118.   for (sym = symtab[h]; sym ; sym = sym->hash_next)
  119.     if (map_to_ns(sym->type) == map_to_ns(type)
  120.     && strcmp(name, sym->name) == 0)
  121.       {
  122.     if (!equal_list(sym->defn, defn))
  123.       error_with_pos("redefinition of %s", name);
  124.     return sym;
  125.       }
  126.  
  127.   sym = xmalloc(sizeof(*sym));
  128.   sym->name = name;
  129.   sym->type = type;
  130.   sym->defn = defn;
  131.   sym->expansion_trail = NULL;
  132.  
  133.   sym->hash_next = symtab[h];
  134.   symtab[h] = sym;
  135.  
  136.   if (flag_debug)
  137.     {
  138.       fprintf(debugfile, "Defn for %s %s == <", symbol_type_name[type],  name);
  139.       print_list(debugfile, defn);
  140.       fputs(">\n", debugfile);
  141.     }
  142.  
  143.   ++nsyms;
  144.   return sym;
  145. }
  146.  
  147.  
  148. /*----------------------------------------------------------------------*/
  149.  
  150. inline void
  151. free_node(struct string_list *node)
  152. {
  153.   free(node->string);
  154.   free(node);
  155. }
  156.  
  157. void
  158. free_list(struct string_list *s, struct string_list *e)
  159. {
  160.   while (s != e)
  161.     {
  162.       struct string_list *next = s->next;
  163.       free_node(s);
  164.       s = next;
  165.     }
  166. }
  167.  
  168. inline struct string_list *
  169. copy_node(struct string_list *node)
  170. {
  171.   struct string_list *newnode;
  172.  
  173.   newnode = xmalloc(sizeof(*newnode));
  174.   newnode->string = xstrdup(node->string);
  175.   newnode->tag = node->tag;
  176.  
  177.   return newnode;
  178. }
  179.  
  180. struct string_list *
  181. copy_list(struct string_list *s, struct string_list *e)
  182. {
  183.   struct string_list *h, *p;
  184.  
  185.   if (s == e)
  186.     return NULL;
  187.  
  188.   p = h = copy_node(s);
  189.   while ((s = s->next) != e)
  190.     p = p->next = copy_node(s);
  191.   p->next = NULL;
  192.  
  193.   return h;
  194. }
  195.  
  196. int
  197. equal_list(struct string_list *a, struct string_list *b)
  198. {
  199.   while (a && b)
  200.     {
  201.       if (a->tag != b->tag || strcmp(a->string, b->string))
  202.     return 0;
  203.       a = a->next;
  204.       b = b->next;
  205.     }
  206.  
  207.   return !a && !b;
  208. }
  209.  
  210. static inline void
  211. print_node(FILE *f, struct string_list *list)
  212. {
  213.   switch (list->tag)
  214.     {
  215.     case SYM_STRUCT:
  216.       putc('s', f);
  217.       goto printit;
  218.     case SYM_UNION:
  219.       putc('u', f);
  220.       goto printit;
  221.     case SYM_ENUM:
  222.       putc('e', f);
  223.       goto printit;
  224.     case SYM_TYPEDEF:
  225.       putc('t', f);
  226.       goto printit;
  227.  
  228.     printit:
  229.       putc('#', f);
  230.     case SYM_NORMAL:
  231.       fputs(list->string, f);
  232.       break;
  233.     }
  234. }
  235.  
  236. void
  237. print_list(FILE *f, struct string_list *list)
  238. {
  239.   struct string_list **e, **b;
  240.   struct string_list *tmp, **tmp2;
  241.   int elem = 1;
  242.  
  243.   if (list == NULL)
  244.     {
  245.       fputs("(nil)", f);
  246.       return;
  247.     }
  248.  
  249.   tmp = list;
  250.   while((tmp = tmp->next) != NULL)
  251.       elem++;
  252.  
  253.   b = alloca(elem * sizeof(*e));
  254.   e = b + elem;
  255.   tmp2 = e - 1;
  256.  
  257.   (*tmp2--) = list;
  258.   while((list = list->next) != NULL)
  259.       *(tmp2--) = list;
  260.  
  261.   while (b != e)
  262.     {
  263.       print_node(f, *b++);
  264.       putc(' ', f);
  265.     }
  266. }
  267.  
  268. static unsigned long
  269. expand_and_crc_list(struct string_list *list, unsigned long crc)
  270. {
  271.   struct string_list **e, **b;
  272.   struct string_list *tmp, **tmp2;
  273.   int elem = 1;
  274.  
  275.   if (!list)
  276.     return crc;
  277.  
  278.   tmp = list;
  279.   while((tmp = tmp->next) != NULL)
  280.       elem++;
  281.  
  282.   b = alloca(elem * sizeof(*e));
  283.   e = b + elem;
  284.   tmp2 = e - 1;
  285.  
  286.   *(tmp2--) = list;
  287.   while ((list = list->next) != NULL)
  288.     *(tmp2--) = list;
  289.  
  290.   while (b != e)
  291.     {
  292.       struct string_list *cur;
  293.       struct symbol *subsym;
  294.  
  295.       cur = *(b++);
  296.       switch (cur->tag)
  297.     {
  298.     case SYM_NORMAL:
  299.       if (flag_dump_defs)
  300.         fprintf(debugfile, "%s ", cur->string);
  301.       crc = partial_crc32(cur->string, crc);
  302.       crc = partial_crc32_one(' ', crc);
  303.       break;
  304.  
  305.     case SYM_TYPEDEF:
  306.       subsym = find_symbol(cur->string, cur->tag);
  307.       if (checksum_version == 1)
  308.         crc = expand_and_crc_list(subsym->defn, crc);
  309.       else if (subsym->expansion_trail)
  310.         {
  311.           if (flag_dump_defs)
  312.         fprintf(debugfile, "%s ", cur->string);
  313.           crc = partial_crc32(cur->string, crc);
  314.           crc = partial_crc32_one(' ', crc);
  315.         }
  316.       else
  317.         {
  318.           subsym->expansion_trail = expansion_trail;
  319.           expansion_trail = subsym;
  320.           crc = expand_and_crc_list(subsym->defn, crc);
  321.         }
  322.       break;
  323.  
  324.     case SYM_STRUCT:
  325.     case SYM_UNION:
  326.     case SYM_ENUM:
  327.       subsym = find_symbol(cur->string, cur->tag);
  328.       if (!subsym)
  329.         {
  330.           struct string_list *n, *t = NULL;
  331.  
  332.           error_with_pos("expand undefined %s %s",
  333.                  symbol_type_name[cur->tag], cur->string);
  334.  
  335.           n = xmalloc(sizeof(*n));
  336.           n->string = xstrdup(symbol_type_name[cur->tag]);
  337.           n->tag = SYM_NORMAL;
  338.           n->next = t;
  339.           t = n;
  340.  
  341.           n = xmalloc(sizeof(*n));
  342.           n->string = xstrdup(cur->string);
  343.           n->tag = SYM_NORMAL;
  344.           n->next = t;
  345.           t = n;
  346.  
  347.           n = xmalloc(sizeof(*n));
  348.           n->string = xstrdup("{ UNKNOWN }");
  349.           n->tag = SYM_NORMAL;
  350.           n->next = t;
  351.  
  352.           subsym = add_symbol(cur->string, cur->tag, n);
  353.         }
  354.       if (subsym->expansion_trail)
  355.         {
  356.           if (flag_dump_defs)
  357.         {
  358.           fprintf(debugfile, "%s %s ", symbol_type_name[cur->tag],
  359.               cur->string);
  360.         }
  361.  
  362.           crc = partial_crc32(symbol_type_name[cur->tag], crc);
  363.           crc = partial_crc32_one(' ', crc);
  364.           crc = partial_crc32(cur->string, crc);
  365.           crc = partial_crc32_one(' ', crc);
  366.         }
  367.       else
  368.         {
  369.           subsym->expansion_trail = expansion_trail;
  370.           expansion_trail = subsym;
  371.           crc = expand_and_crc_list(subsym->defn, crc);
  372.         }
  373.       break;
  374.     }
  375.     }
  376.  
  377.   return crc;
  378. }
  379.  
  380. void
  381. export_symbol(const char *name)
  382. {
  383.   struct symbol *sym;
  384.  
  385.   sym = find_symbol(name, SYM_NORMAL);
  386.   if (!sym)
  387.     error_with_pos("export undefined symbol %s", name);
  388.   else
  389.     {
  390.       unsigned long crc;
  391.  
  392.       if (flag_dump_defs)
  393.     fprintf(debugfile, "Export %s == <", name);
  394.  
  395.       expansion_trail = (struct symbol *)-1L;
  396.  
  397.       crc = expand_and_crc_list(sym->defn, 0xffffffff) ^ 0xffffffff;
  398.  
  399.       sym = expansion_trail;
  400.       while (sym != (struct symbol *)-1L)
  401.     {
  402.       struct symbol *n = sym->expansion_trail;
  403.       sym->expansion_trail = 0;
  404.       sym = n;
  405.     }
  406.  
  407.       if (flag_dump_defs)
  408.     fputs(">\n", debugfile);
  409.  
  410.       if (checksum_version > 1)
  411.     {
  412.       fprintf(outfile, "#define __ver_%s\t%s%08lx\n", name,
  413.           crc_prefix, crc);
  414.       fprintf(outfile, "#define %s\t_set_ver(%s)\n", name, name);
  415.     }
  416.       else
  417.     {
  418.       fprintf(outfile, "#define %s\t_set_ver(%s, %s%08lx)\n", name, name,
  419.           crc_prefix, crc);
  420.     }
  421.     }
  422. }
  423.  
  424.  
  425. /*----------------------------------------------------------------------*/
  426.  
  427. void
  428. error(const char *fmt, ...)
  429. {
  430.   va_list args;
  431.  
  432.   if (flag_warnings)
  433.     {
  434.       va_start(args, fmt);
  435.       vfprintf(stderr, fmt, args);
  436.       va_end(args);
  437.       putc('\n', stderr);
  438.  
  439.       errors++;
  440.     }
  441. }
  442.  
  443. void
  444. error_with_pos(const char *fmt, ...)
  445. {
  446.   va_list args;
  447.  
  448.   if (flag_warnings)
  449.     {
  450.       fprintf(stderr, "%s:%d: ", cur_filename ? : "<stdin>", cur_line);
  451.  
  452.       va_start(args, fmt);
  453.       vfprintf(stderr, fmt, args);
  454.       va_end(args);
  455.       putc('\n', stderr);
  456.  
  457.       errors++;
  458.     }
  459. }
  460.  
  461.  
  462. int
  463. main(int argc, char **argv)
  464. {
  465.   int o;
  466.  
  467.   while ((o = getopt(argc, argv, "dgwqVDk:p:")) != EOF)
  468.     switch (o)
  469.       {
  470.       case 'd':
  471.     flag_debug++;
  472.     break;
  473.       case 'g':
  474.     flag_export_globals = 1;
  475.     break;
  476.       case 'w':
  477.     flag_warnings = 1;
  478.     break;
  479.       case 'q':
  480.     flag_warnings = 0;
  481.     break;
  482.       case 'V':
  483.         fputs("genksyms version " MODUTILS_VERSION "\n", stderr);
  484.     break;
  485.       case 'D':
  486.     flag_dump_defs = 1;
  487.     break;
  488.       case 'k':
  489.     {
  490.       char *p;
  491.       int a, b, c;
  492.  
  493.       p = optarg;
  494.       a = strtoul(p, &p, 10);
  495.       if (*p != '.')
  496.         return -1;
  497.       b = strtoul(p+1, &p, 10);
  498.       if (*p != '.')
  499.         return -1;
  500.       c = strtoul(p+1, &p, 10);
  501.       if (*p != '\0')
  502.         return -1;
  503.  
  504.       kernel_version = a << 16 | b << 8 | c;
  505.     }
  506.         break;
  507.       case 'p':
  508.     crc_prefix = optarg;
  509.     break;
  510.  
  511.       default:
  512.       usage:
  513.     fputs("Usage:\n"
  514.           "genksyms [-dDwqV] -k kernel_version > .../linux/module/*.ver\n"
  515.           "\n"
  516.           "  -d        Debug level -- repeat to increase\n"
  517.           "  -D        Dump final exported definitions\n"
  518.           "  -w        Enable warnings (aka errors)\n"
  519.           "  -q        Disable warnings (default)\n"
  520.           "  -V        Show version\n"
  521.           "  -k ver    Set the kernel version for which we are compiling\n"
  522.           "  -p string Set a mangling prefix for all symbols\n"
  523.           , stderr);
  524.     return 1;
  525.       }
  526.  
  527.   if (kernel_version >= version(2,1,18))
  528.     {
  529.       if (optind != argc)
  530.     goto usage;
  531.  
  532.       /* Exporting all globals is depreciated.  */
  533.       if (flag_export_globals)
  534.     goto usage;
  535.  
  536.       /* For newer kernels, eliminate some irrelevant constructs.  */
  537.       checksum_version = 2;
  538.  
  539.       outfile = stdout;
  540.     }
  541.   else
  542.     {
  543.       if (optind+1 != argc)
  544.     goto usage;
  545.       output_directory = argv[optind];
  546.     }
  547.  
  548.     {
  549.       extern int yydebug;
  550.       extern int yy_flex_debug;
  551.  
  552.       yydebug = (flag_debug > 1);
  553.       yy_flex_debug = (flag_debug > 2);
  554.  
  555.       debugfile = stderr;
  556.       /* setlinebuf(debugfile); */
  557.     }
  558.  
  559.   yyparse();
  560.  
  561.   if (flag_export_globals)
  562.     {
  563.       /* FIXME */
  564.     }
  565.  
  566.   if (checksum_version == 1)
  567.     {
  568.       fputs("#endif\n#endif\n", outfile);
  569.     }
  570.  
  571.   if (flag_debug)
  572.     {
  573.       fprintf(debugfile, "Hash table occupancy %d/%d = %g\n",
  574.           nsyms, HASH_BUCKETS, (double)nsyms / (double)HASH_BUCKETS);
  575.     }
  576.  
  577.   return errors != 0;
  578. }
  579.