Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /* Generate kernel symbol version hashes.
0003    Copyright 1996, 1997 Linux International.
0004 
0005    New implementation contributed by Richard Henderson <rth@tamu.edu>
0006    Based on original work by Bjorn Ekwall <bj0rn@blox.se>
0007 
0008    This file was part of the Linux modutils 2.4.22: moved back into the
0009    kernel sources by Rusty Russell/Kai Germaschewski.
0010 
0011  */
0012 
0013 #include <stdio.h>
0014 #include <string.h>
0015 #include <stdlib.h>
0016 #include <unistd.h>
0017 #include <assert.h>
0018 #include <stdarg.h>
0019 #ifdef __GNU_LIBRARY__
0020 #include <getopt.h>
0021 #endif              /* __GNU_LIBRARY__ */
0022 
0023 #include "genksyms.h"
0024 /*----------------------------------------------------------------------*/
0025 
0026 #define HASH_BUCKETS  4096
0027 
0028 static struct symbol *symtab[HASH_BUCKETS];
0029 static FILE *debugfile;
0030 
0031 int cur_line = 1;
0032 char *cur_filename;
0033 int in_source_file;
0034 
0035 static int flag_debug, flag_dump_defs, flag_reference, flag_dump_types,
0036        flag_preserve, flag_warnings;
0037 
0038 static int errors;
0039 static int nsyms;
0040 
0041 static struct symbol *expansion_trail;
0042 static struct symbol *visited_symbols;
0043 
0044 static const struct {
0045     int n;
0046     const char *name;
0047 } symbol_types[] = {
0048     [SYM_NORMAL]     = { 0, NULL},
0049     [SYM_TYPEDEF]    = {'t', "typedef"},
0050     [SYM_ENUM]       = {'e', "enum"},
0051     [SYM_STRUCT]     = {'s', "struct"},
0052     [SYM_UNION]      = {'u', "union"},
0053     [SYM_ENUM_CONST] = {'E', "enum constant"},
0054 };
0055 
0056 static int equal_list(struct string_list *a, struct string_list *b);
0057 static void print_list(FILE * f, struct string_list *list);
0058 static struct string_list *concat_list(struct string_list *start, ...);
0059 static struct string_list *mk_node(const char *string);
0060 static void print_location(void);
0061 static void print_type_name(enum symbol_type type, const char *name);
0062 
0063 /*----------------------------------------------------------------------*/
0064 
0065 static const unsigned int crctab32[] = {
0066     0x00000000U, 0x77073096U, 0xee0e612cU, 0x990951baU, 0x076dc419U,
0067     0x706af48fU, 0xe963a535U, 0x9e6495a3U, 0x0edb8832U, 0x79dcb8a4U,
0068     0xe0d5e91eU, 0x97d2d988U, 0x09b64c2bU, 0x7eb17cbdU, 0xe7b82d07U,
0069     0x90bf1d91U, 0x1db71064U, 0x6ab020f2U, 0xf3b97148U, 0x84be41deU,
0070     0x1adad47dU, 0x6ddde4ebU, 0xf4d4b551U, 0x83d385c7U, 0x136c9856U,
0071     0x646ba8c0U, 0xfd62f97aU, 0x8a65c9ecU, 0x14015c4fU, 0x63066cd9U,
0072     0xfa0f3d63U, 0x8d080df5U, 0x3b6e20c8U, 0x4c69105eU, 0xd56041e4U,
0073     0xa2677172U, 0x3c03e4d1U, 0x4b04d447U, 0xd20d85fdU, 0xa50ab56bU,
0074     0x35b5a8faU, 0x42b2986cU, 0xdbbbc9d6U, 0xacbcf940U, 0x32d86ce3U,
0075     0x45df5c75U, 0xdcd60dcfU, 0xabd13d59U, 0x26d930acU, 0x51de003aU,
0076     0xc8d75180U, 0xbfd06116U, 0x21b4f4b5U, 0x56b3c423U, 0xcfba9599U,
0077     0xb8bda50fU, 0x2802b89eU, 0x5f058808U, 0xc60cd9b2U, 0xb10be924U,
0078     0x2f6f7c87U, 0x58684c11U, 0xc1611dabU, 0xb6662d3dU, 0x76dc4190U,
0079     0x01db7106U, 0x98d220bcU, 0xefd5102aU, 0x71b18589U, 0x06b6b51fU,
0080     0x9fbfe4a5U, 0xe8b8d433U, 0x7807c9a2U, 0x0f00f934U, 0x9609a88eU,
0081     0xe10e9818U, 0x7f6a0dbbU, 0x086d3d2dU, 0x91646c97U, 0xe6635c01U,
0082     0x6b6b51f4U, 0x1c6c6162U, 0x856530d8U, 0xf262004eU, 0x6c0695edU,
0083     0x1b01a57bU, 0x8208f4c1U, 0xf50fc457U, 0x65b0d9c6U, 0x12b7e950U,
0084     0x8bbeb8eaU, 0xfcb9887cU, 0x62dd1ddfU, 0x15da2d49U, 0x8cd37cf3U,
0085     0xfbd44c65U, 0x4db26158U, 0x3ab551ceU, 0xa3bc0074U, 0xd4bb30e2U,
0086     0x4adfa541U, 0x3dd895d7U, 0xa4d1c46dU, 0xd3d6f4fbU, 0x4369e96aU,
0087     0x346ed9fcU, 0xad678846U, 0xda60b8d0U, 0x44042d73U, 0x33031de5U,
0088     0xaa0a4c5fU, 0xdd0d7cc9U, 0x5005713cU, 0x270241aaU, 0xbe0b1010U,
0089     0xc90c2086U, 0x5768b525U, 0x206f85b3U, 0xb966d409U, 0xce61e49fU,
0090     0x5edef90eU, 0x29d9c998U, 0xb0d09822U, 0xc7d7a8b4U, 0x59b33d17U,
0091     0x2eb40d81U, 0xb7bd5c3bU, 0xc0ba6cadU, 0xedb88320U, 0x9abfb3b6U,
0092     0x03b6e20cU, 0x74b1d29aU, 0xead54739U, 0x9dd277afU, 0x04db2615U,
0093     0x73dc1683U, 0xe3630b12U, 0x94643b84U, 0x0d6d6a3eU, 0x7a6a5aa8U,
0094     0xe40ecf0bU, 0x9309ff9dU, 0x0a00ae27U, 0x7d079eb1U, 0xf00f9344U,
0095     0x8708a3d2U, 0x1e01f268U, 0x6906c2feU, 0xf762575dU, 0x806567cbU,
0096     0x196c3671U, 0x6e6b06e7U, 0xfed41b76U, 0x89d32be0U, 0x10da7a5aU,
0097     0x67dd4accU, 0xf9b9df6fU, 0x8ebeeff9U, 0x17b7be43U, 0x60b08ed5U,
0098     0xd6d6a3e8U, 0xa1d1937eU, 0x38d8c2c4U, 0x4fdff252U, 0xd1bb67f1U,
0099     0xa6bc5767U, 0x3fb506ddU, 0x48b2364bU, 0xd80d2bdaU, 0xaf0a1b4cU,
0100     0x36034af6U, 0x41047a60U, 0xdf60efc3U, 0xa867df55U, 0x316e8eefU,
0101     0x4669be79U, 0xcb61b38cU, 0xbc66831aU, 0x256fd2a0U, 0x5268e236U,
0102     0xcc0c7795U, 0xbb0b4703U, 0x220216b9U, 0x5505262fU, 0xc5ba3bbeU,
0103     0xb2bd0b28U, 0x2bb45a92U, 0x5cb36a04U, 0xc2d7ffa7U, 0xb5d0cf31U,
0104     0x2cd99e8bU, 0x5bdeae1dU, 0x9b64c2b0U, 0xec63f226U, 0x756aa39cU,
0105     0x026d930aU, 0x9c0906a9U, 0xeb0e363fU, 0x72076785U, 0x05005713U,
0106     0x95bf4a82U, 0xe2b87a14U, 0x7bb12baeU, 0x0cb61b38U, 0x92d28e9bU,
0107     0xe5d5be0dU, 0x7cdcefb7U, 0x0bdbdf21U, 0x86d3d2d4U, 0xf1d4e242U,
0108     0x68ddb3f8U, 0x1fda836eU, 0x81be16cdU, 0xf6b9265bU, 0x6fb077e1U,
0109     0x18b74777U, 0x88085ae6U, 0xff0f6a70U, 0x66063bcaU, 0x11010b5cU,
0110     0x8f659effU, 0xf862ae69U, 0x616bffd3U, 0x166ccf45U, 0xa00ae278U,
0111     0xd70dd2eeU, 0x4e048354U, 0x3903b3c2U, 0xa7672661U, 0xd06016f7U,
0112     0x4969474dU, 0x3e6e77dbU, 0xaed16a4aU, 0xd9d65adcU, 0x40df0b66U,
0113     0x37d83bf0U, 0xa9bcae53U, 0xdebb9ec5U, 0x47b2cf7fU, 0x30b5ffe9U,
0114     0xbdbdf21cU, 0xcabac28aU, 0x53b39330U, 0x24b4a3a6U, 0xbad03605U,
0115     0xcdd70693U, 0x54de5729U, 0x23d967bfU, 0xb3667a2eU, 0xc4614ab8U,
0116     0x5d681b02U, 0x2a6f2b94U, 0xb40bbe37U, 0xc30c8ea1U, 0x5a05df1bU,
0117     0x2d02ef8dU
0118 };
0119 
0120 static unsigned long partial_crc32_one(unsigned char c, unsigned long crc)
0121 {
0122     return crctab32[(crc ^ c) & 0xff] ^ (crc >> 8);
0123 }
0124 
0125 static unsigned long partial_crc32(const char *s, unsigned long crc)
0126 {
0127     while (*s)
0128         crc = partial_crc32_one(*s++, crc);
0129     return crc;
0130 }
0131 
0132 static unsigned long crc32(const char *s)
0133 {
0134     return partial_crc32(s, 0xffffffff) ^ 0xffffffff;
0135 }
0136 
0137 /*----------------------------------------------------------------------*/
0138 
0139 static enum symbol_type map_to_ns(enum symbol_type t)
0140 {
0141     switch (t) {
0142     case SYM_ENUM_CONST:
0143     case SYM_NORMAL:
0144     case SYM_TYPEDEF:
0145         return SYM_NORMAL;
0146     case SYM_ENUM:
0147     case SYM_STRUCT:
0148     case SYM_UNION:
0149         return SYM_STRUCT;
0150     }
0151     return t;
0152 }
0153 
0154 struct symbol *find_symbol(const char *name, enum symbol_type ns, int exact)
0155 {
0156     unsigned long h = crc32(name) % HASH_BUCKETS;
0157     struct symbol *sym;
0158 
0159     for (sym = symtab[h]; sym; sym = sym->hash_next)
0160         if (map_to_ns(sym->type) == map_to_ns(ns) &&
0161             strcmp(name, sym->name) == 0 &&
0162             sym->is_declared)
0163             break;
0164 
0165     if (exact && sym && sym->type != ns)
0166         return NULL;
0167     return sym;
0168 }
0169 
0170 static int is_unknown_symbol(struct symbol *sym)
0171 {
0172     struct string_list *defn;
0173 
0174     return ((sym->type == SYM_STRUCT ||
0175          sym->type == SYM_UNION ||
0176          sym->type == SYM_ENUM) &&
0177         (defn = sym->defn)  && defn->tag == SYM_NORMAL &&
0178             strcmp(defn->string, "}") == 0 &&
0179         (defn = defn->next) && defn->tag == SYM_NORMAL &&
0180             strcmp(defn->string, "UNKNOWN") == 0 &&
0181         (defn = defn->next) && defn->tag == SYM_NORMAL &&
0182             strcmp(defn->string, "{") == 0);
0183 }
0184 
0185 static struct symbol *__add_symbol(const char *name, enum symbol_type type,
0186                 struct string_list *defn, int is_extern,
0187                 int is_reference)
0188 {
0189     unsigned long h;
0190     struct symbol *sym;
0191     enum symbol_status status = STATUS_UNCHANGED;
0192     /* The parser adds symbols in the order their declaration completes,
0193      * so it is safe to store the value of the previous enum constant in
0194      * a static variable.
0195      */
0196     static int enum_counter;
0197     static struct string_list *last_enum_expr;
0198 
0199     if (type == SYM_ENUM_CONST) {
0200         if (defn) {
0201             free_list(last_enum_expr, NULL);
0202             last_enum_expr = copy_list_range(defn, NULL);
0203             enum_counter = 1;
0204         } else {
0205             struct string_list *expr;
0206             char buf[20];
0207 
0208             snprintf(buf, sizeof(buf), "%d", enum_counter++);
0209             if (last_enum_expr) {
0210                 expr = copy_list_range(last_enum_expr, NULL);
0211                 defn = concat_list(mk_node("("),
0212                            expr,
0213                            mk_node(")"),
0214                            mk_node("+"),
0215                            mk_node(buf), NULL);
0216             } else {
0217                 defn = mk_node(buf);
0218             }
0219         }
0220     } else if (type == SYM_ENUM) {
0221         free_list(last_enum_expr, NULL);
0222         last_enum_expr = NULL;
0223         enum_counter = 0;
0224         if (!name)
0225             /* Anonymous enum definition, nothing more to do */
0226             return NULL;
0227     }
0228 
0229     h = crc32(name) % HASH_BUCKETS;
0230     for (sym = symtab[h]; sym; sym = sym->hash_next) {
0231         if (map_to_ns(sym->type) == map_to_ns(type) &&
0232             strcmp(name, sym->name) == 0) {
0233             if (is_reference)
0234                 /* fall through */ ;
0235             else if (sym->type == type &&
0236                  equal_list(sym->defn, defn)) {
0237                 if (!sym->is_declared && sym->is_override) {
0238                     print_location();
0239                     print_type_name(type, name);
0240                     fprintf(stderr, " modversion is "
0241                         "unchanged\n");
0242                 }
0243                 sym->is_declared = 1;
0244                 return sym;
0245             } else if (!sym->is_declared) {
0246                 if (sym->is_override && flag_preserve) {
0247                     print_location();
0248                     fprintf(stderr, "ignoring ");
0249                     print_type_name(type, name);
0250                     fprintf(stderr, " modversion change\n");
0251                     sym->is_declared = 1;
0252                     return sym;
0253                 } else {
0254                     status = is_unknown_symbol(sym) ?
0255                         STATUS_DEFINED : STATUS_MODIFIED;
0256                 }
0257             } else {
0258                 error_with_pos("redefinition of %s", name);
0259                 return sym;
0260             }
0261             break;
0262         }
0263     }
0264 
0265     if (sym) {
0266         struct symbol **psym;
0267 
0268         for (psym = &symtab[h]; *psym; psym = &(*psym)->hash_next) {
0269             if (*psym == sym) {
0270                 *psym = sym->hash_next;
0271                 break;
0272             }
0273         }
0274         --nsyms;
0275     }
0276 
0277     sym = xmalloc(sizeof(*sym));
0278     sym->name = name;
0279     sym->type = type;
0280     sym->defn = defn;
0281     sym->expansion_trail = NULL;
0282     sym->visited = NULL;
0283     sym->is_extern = is_extern;
0284 
0285     sym->hash_next = symtab[h];
0286     symtab[h] = sym;
0287 
0288     sym->is_declared = !is_reference;
0289     sym->status = status;
0290     sym->is_override = 0;
0291 
0292     if (flag_debug) {
0293         if (symbol_types[type].name)
0294             fprintf(debugfile, "Defn for %s %s == <",
0295                 symbol_types[type].name, name);
0296         else
0297             fprintf(debugfile, "Defn for type%d %s == <",
0298                 type, name);
0299         if (is_extern)
0300             fputs("extern ", debugfile);
0301         print_list(debugfile, defn);
0302         fputs(">\n", debugfile);
0303     }
0304 
0305     ++nsyms;
0306     return sym;
0307 }
0308 
0309 struct symbol *add_symbol(const char *name, enum symbol_type type,
0310               struct string_list *defn, int is_extern)
0311 {
0312     return __add_symbol(name, type, defn, is_extern, 0);
0313 }
0314 
0315 static struct symbol *add_reference_symbol(const char *name, enum symbol_type type,
0316                     struct string_list *defn, int is_extern)
0317 {
0318     return __add_symbol(name, type, defn, is_extern, 1);
0319 }
0320 
0321 /*----------------------------------------------------------------------*/
0322 
0323 void free_node(struct string_list *node)
0324 {
0325     free(node->string);
0326     free(node);
0327 }
0328 
0329 void free_list(struct string_list *s, struct string_list *e)
0330 {
0331     while (s != e) {
0332         struct string_list *next = s->next;
0333         free_node(s);
0334         s = next;
0335     }
0336 }
0337 
0338 static struct string_list *mk_node(const char *string)
0339 {
0340     struct string_list *newnode;
0341 
0342     newnode = xmalloc(sizeof(*newnode));
0343     newnode->string = xstrdup(string);
0344     newnode->tag = SYM_NORMAL;
0345     newnode->next = NULL;
0346 
0347     return newnode;
0348 }
0349 
0350 static struct string_list *concat_list(struct string_list *start, ...)
0351 {
0352     va_list ap;
0353     struct string_list *n, *n2;
0354 
0355     if (!start)
0356         return NULL;
0357     for (va_start(ap, start); (n = va_arg(ap, struct string_list *));) {
0358         for (n2 = n; n2->next; n2 = n2->next)
0359             ;
0360         n2->next = start;
0361         start = n;
0362     }
0363     va_end(ap);
0364     return start;
0365 }
0366 
0367 struct string_list *copy_node(struct string_list *node)
0368 {
0369     struct string_list *newnode;
0370 
0371     newnode = xmalloc(sizeof(*newnode));
0372     newnode->string = xstrdup(node->string);
0373     newnode->tag = node->tag;
0374 
0375     return newnode;
0376 }
0377 
0378 struct string_list *copy_list_range(struct string_list *start,
0379                     struct string_list *end)
0380 {
0381     struct string_list *res, *n;
0382 
0383     if (start == end)
0384         return NULL;
0385     n = res = copy_node(start);
0386     for (start = start->next; start != end; start = start->next) {
0387         n->next = copy_node(start);
0388         n = n->next;
0389     }
0390     n->next = NULL;
0391     return res;
0392 }
0393 
0394 static int equal_list(struct string_list *a, struct string_list *b)
0395 {
0396     while (a && b) {
0397         if (a->tag != b->tag || strcmp(a->string, b->string))
0398             return 0;
0399         a = a->next;
0400         b = b->next;
0401     }
0402 
0403     return !a && !b;
0404 }
0405 
0406 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
0407 
0408 static struct string_list *read_node(FILE *f)
0409 {
0410     char buffer[256];
0411     struct string_list node = {
0412         .string = buffer,
0413         .tag = SYM_NORMAL };
0414     int c, in_string = 0;
0415 
0416     while ((c = fgetc(f)) != EOF) {
0417         if (!in_string && c == ' ') {
0418             if (node.string == buffer)
0419                 continue;
0420             break;
0421         } else if (c == '"') {
0422             in_string = !in_string;
0423         } else if (c == '\n') {
0424             if (node.string == buffer)
0425                 return NULL;
0426             ungetc(c, f);
0427             break;
0428         }
0429         if (node.string >= buffer + sizeof(buffer) - 1) {
0430             fprintf(stderr, "Token too long\n");
0431             exit(1);
0432         }
0433         *node.string++ = c;
0434     }
0435     if (node.string == buffer)
0436         return NULL;
0437     *node.string = 0;
0438     node.string = buffer;
0439 
0440     if (node.string[1] == '#') {
0441         size_t n;
0442 
0443         for (n = 0; n < ARRAY_SIZE(symbol_types); n++) {
0444             if (node.string[0] == symbol_types[n].n) {
0445                 node.tag = n;
0446                 node.string += 2;
0447                 return copy_node(&node);
0448             }
0449         }
0450         fprintf(stderr, "Unknown type %c\n", node.string[0]);
0451         exit(1);
0452     }
0453     return copy_node(&node);
0454 }
0455 
0456 static void read_reference(FILE *f)
0457 {
0458     while (!feof(f)) {
0459         struct string_list *defn = NULL;
0460         struct string_list *sym, *def;
0461         int is_extern = 0, is_override = 0;
0462         struct symbol *subsym;
0463 
0464         sym = read_node(f);
0465         if (sym && sym->tag == SYM_NORMAL &&
0466             !strcmp(sym->string, "override")) {
0467             is_override = 1;
0468             free_node(sym);
0469             sym = read_node(f);
0470         }
0471         if (!sym)
0472             continue;
0473         def = read_node(f);
0474         if (def && def->tag == SYM_NORMAL &&
0475             !strcmp(def->string, "extern")) {
0476             is_extern = 1;
0477             free_node(def);
0478             def = read_node(f);
0479         }
0480         while (def) {
0481             def->next = defn;
0482             defn = def;
0483             def = read_node(f);
0484         }
0485         subsym = add_reference_symbol(xstrdup(sym->string), sym->tag,
0486                           defn, is_extern);
0487         subsym->is_override = is_override;
0488         free_node(sym);
0489     }
0490 }
0491 
0492 static void print_node(FILE * f, struct string_list *list)
0493 {
0494     if (symbol_types[list->tag].n) {
0495         putc(symbol_types[list->tag].n, f);
0496         putc('#', f);
0497     }
0498     fputs(list->string, f);
0499 }
0500 
0501 static void print_list(FILE * f, struct string_list *list)
0502 {
0503     struct string_list **e, **b;
0504     struct string_list *tmp, **tmp2;
0505     int elem = 1;
0506 
0507     if (list == NULL) {
0508         fputs("(nil)", f);
0509         return;
0510     }
0511 
0512     tmp = list;
0513     while ((tmp = tmp->next) != NULL)
0514         elem++;
0515 
0516     b = alloca(elem * sizeof(*e));
0517     e = b + elem;
0518     tmp2 = e - 1;
0519 
0520     (*tmp2--) = list;
0521     while ((list = list->next) != NULL)
0522         *(tmp2--) = list;
0523 
0524     while (b != e) {
0525         print_node(f, *b++);
0526         putc(' ', f);
0527     }
0528 }
0529 
0530 static unsigned long expand_and_crc_sym(struct symbol *sym, unsigned long crc)
0531 {
0532     struct string_list *list = sym->defn;
0533     struct string_list **e, **b;
0534     struct string_list *tmp, **tmp2;
0535     int elem = 1;
0536 
0537     if (!list)
0538         return crc;
0539 
0540     tmp = list;
0541     while ((tmp = tmp->next) != NULL)
0542         elem++;
0543 
0544     b = alloca(elem * sizeof(*e));
0545     e = b + elem;
0546     tmp2 = e - 1;
0547 
0548     *(tmp2--) = list;
0549     while ((list = list->next) != NULL)
0550         *(tmp2--) = list;
0551 
0552     while (b != e) {
0553         struct string_list *cur;
0554         struct symbol *subsym;
0555 
0556         cur = *(b++);
0557         switch (cur->tag) {
0558         case SYM_NORMAL:
0559             if (flag_dump_defs)
0560                 fprintf(debugfile, "%s ", cur->string);
0561             crc = partial_crc32(cur->string, crc);
0562             crc = partial_crc32_one(' ', crc);
0563             break;
0564 
0565         case SYM_ENUM_CONST:
0566         case SYM_TYPEDEF:
0567             subsym = find_symbol(cur->string, cur->tag, 0);
0568             /* FIXME: Bad reference files can segfault here. */
0569             if (subsym->expansion_trail) {
0570                 if (flag_dump_defs)
0571                     fprintf(debugfile, "%s ", cur->string);
0572                 crc = partial_crc32(cur->string, crc);
0573                 crc = partial_crc32_one(' ', crc);
0574             } else {
0575                 subsym->expansion_trail = expansion_trail;
0576                 expansion_trail = subsym;
0577                 crc = expand_and_crc_sym(subsym, crc);
0578             }
0579             break;
0580 
0581         case SYM_STRUCT:
0582         case SYM_UNION:
0583         case SYM_ENUM:
0584             subsym = find_symbol(cur->string, cur->tag, 0);
0585             if (!subsym) {
0586                 struct string_list *n;
0587 
0588                 error_with_pos("expand undefined %s %s",
0589                            symbol_types[cur->tag].name,
0590                            cur->string);
0591                 n = concat_list(mk_node
0592                         (symbol_types[cur->tag].name),
0593                         mk_node(cur->string),
0594                         mk_node("{"),
0595                         mk_node("UNKNOWN"),
0596                         mk_node("}"), NULL);
0597                 subsym =
0598                     add_symbol(cur->string, cur->tag, n, 0);
0599             }
0600             if (subsym->expansion_trail) {
0601                 if (flag_dump_defs) {
0602                     fprintf(debugfile, "%s %s ",
0603                         symbol_types[cur->tag].name,
0604                         cur->string);
0605                 }
0606 
0607                 crc = partial_crc32(symbol_types[cur->tag].name,
0608                             crc);
0609                 crc = partial_crc32_one(' ', crc);
0610                 crc = partial_crc32(cur->string, crc);
0611                 crc = partial_crc32_one(' ', crc);
0612             } else {
0613                 subsym->expansion_trail = expansion_trail;
0614                 expansion_trail = subsym;
0615                 crc = expand_and_crc_sym(subsym, crc);
0616             }
0617             break;
0618         }
0619     }
0620 
0621     {
0622         static struct symbol **end = &visited_symbols;
0623 
0624         if (!sym->visited) {
0625             *end = sym;
0626             end = &sym->visited;
0627             sym->visited = (struct symbol *)-1L;
0628         }
0629     }
0630 
0631     return crc;
0632 }
0633 
0634 void export_symbol(const char *name)
0635 {
0636     struct symbol *sym;
0637 
0638     sym = find_symbol(name, SYM_NORMAL, 0);
0639     if (!sym)
0640         error_with_pos("export undefined symbol %s", name);
0641     else {
0642         unsigned long crc;
0643         int has_changed = 0;
0644 
0645         if (flag_dump_defs)
0646             fprintf(debugfile, "Export %s == <", name);
0647 
0648         expansion_trail = (struct symbol *)-1L;
0649 
0650         sym->expansion_trail = expansion_trail;
0651         expansion_trail = sym;
0652         crc = expand_and_crc_sym(sym, 0xffffffff) ^ 0xffffffff;
0653 
0654         sym = expansion_trail;
0655         while (sym != (struct symbol *)-1L) {
0656             struct symbol *n = sym->expansion_trail;
0657 
0658             if (sym->status != STATUS_UNCHANGED) {
0659                 if (!has_changed) {
0660                     print_location();
0661                     fprintf(stderr, "%s: %s: modversion "
0662                         "changed because of changes "
0663                         "in ", flag_preserve ? "error" :
0664                                "warning", name);
0665                 } else
0666                     fprintf(stderr, ", ");
0667                 print_type_name(sym->type, sym->name);
0668                 if (sym->status == STATUS_DEFINED)
0669                     fprintf(stderr, " (became defined)");
0670                 has_changed = 1;
0671                 if (flag_preserve)
0672                     errors++;
0673             }
0674             sym->expansion_trail = 0;
0675             sym = n;
0676         }
0677         if (has_changed)
0678             fprintf(stderr, "\n");
0679 
0680         if (flag_dump_defs)
0681             fputs(">\n", debugfile);
0682 
0683         printf("#SYMVER %s 0x%08lx\n", name, crc);
0684     }
0685 }
0686 
0687 /*----------------------------------------------------------------------*/
0688 
0689 static void print_location(void)
0690 {
0691     fprintf(stderr, "%s:%d: ", cur_filename ? : "<stdin>", cur_line);
0692 }
0693 
0694 static void print_type_name(enum symbol_type type, const char *name)
0695 {
0696     if (symbol_types[type].name)
0697         fprintf(stderr, "%s %s", symbol_types[type].name, name);
0698     else
0699         fprintf(stderr, "%s", name);
0700 }
0701 
0702 void error_with_pos(const char *fmt, ...)
0703 {
0704     va_list args;
0705 
0706     if (flag_warnings) {
0707         print_location();
0708 
0709         va_start(args, fmt);
0710         vfprintf(stderr, fmt, args);
0711         va_end(args);
0712         putc('\n', stderr);
0713 
0714         errors++;
0715     }
0716 }
0717 
0718 static void genksyms_usage(void)
0719 {
0720     fputs("Usage:\n" "genksyms [-adDTwqhVR] > /path/to/.tmp_obj.ver\n" "\n"
0721 #ifdef __GNU_LIBRARY__
0722           "  -s, --symbol-prefix   Select symbol prefix\n"
0723           "  -d, --debug           Increment the debug level (repeatable)\n"
0724           "  -D, --dump            Dump expanded symbol defs (for debugging only)\n"
0725           "  -r, --reference file  Read reference symbols from a file\n"
0726           "  -T, --dump-types file Dump expanded types into file\n"
0727           "  -p, --preserve        Preserve reference modversions or fail\n"
0728           "  -w, --warnings        Enable warnings\n"
0729           "  -q, --quiet           Disable warnings (default)\n"
0730           "  -h, --help            Print this message\n"
0731           "  -V, --version         Print the release version\n"
0732 #else               /* __GNU_LIBRARY__ */
0733           "  -s                    Select symbol prefix\n"
0734           "  -d                    Increment the debug level (repeatable)\n"
0735           "  -D                    Dump expanded symbol defs (for debugging only)\n"
0736           "  -r file               Read reference symbols from a file\n"
0737           "  -T file               Dump expanded types into file\n"
0738           "  -p                    Preserve reference modversions or fail\n"
0739           "  -w                    Enable warnings\n"
0740           "  -q                    Disable warnings (default)\n"
0741           "  -h                    Print this message\n"
0742           "  -V                    Print the release version\n"
0743 #endif              /* __GNU_LIBRARY__ */
0744           , stderr);
0745 }
0746 
0747 int main(int argc, char **argv)
0748 {
0749     FILE *dumpfile = NULL, *ref_file = NULL;
0750     int o;
0751 
0752 #ifdef __GNU_LIBRARY__
0753     struct option long_opts[] = {
0754         {"debug", 0, 0, 'd'},
0755         {"warnings", 0, 0, 'w'},
0756         {"quiet", 0, 0, 'q'},
0757         {"dump", 0, 0, 'D'},
0758         {"reference", 1, 0, 'r'},
0759         {"dump-types", 1, 0, 'T'},
0760         {"preserve", 0, 0, 'p'},
0761         {"version", 0, 0, 'V'},
0762         {"help", 0, 0, 'h'},
0763         {0, 0, 0, 0}
0764     };
0765 
0766     while ((o = getopt_long(argc, argv, "s:dwqVDr:T:ph",
0767                 &long_opts[0], NULL)) != EOF)
0768 #else               /* __GNU_LIBRARY__ */
0769     while ((o = getopt(argc, argv, "s:dwqVDr:T:ph")) != EOF)
0770 #endif              /* __GNU_LIBRARY__ */
0771         switch (o) {
0772         case 'd':
0773             flag_debug++;
0774             break;
0775         case 'w':
0776             flag_warnings = 1;
0777             break;
0778         case 'q':
0779             flag_warnings = 0;
0780             break;
0781         case 'V':
0782             fputs("genksyms version 2.5.60\n", stderr);
0783             break;
0784         case 'D':
0785             flag_dump_defs = 1;
0786             break;
0787         case 'r':
0788             flag_reference = 1;
0789             ref_file = fopen(optarg, "r");
0790             if (!ref_file) {
0791                 perror(optarg);
0792                 return 1;
0793             }
0794             break;
0795         case 'T':
0796             flag_dump_types = 1;
0797             dumpfile = fopen(optarg, "w");
0798             if (!dumpfile) {
0799                 perror(optarg);
0800                 return 1;
0801             }
0802             break;
0803         case 'p':
0804             flag_preserve = 1;
0805             break;
0806         case 'h':
0807             genksyms_usage();
0808             return 0;
0809         default:
0810             genksyms_usage();
0811             return 1;
0812         }
0813     {
0814         extern int yydebug;
0815         extern int yy_flex_debug;
0816 
0817         yydebug = (flag_debug > 1);
0818         yy_flex_debug = (flag_debug > 2);
0819 
0820         debugfile = stderr;
0821         /* setlinebuf(debugfile); */
0822     }
0823 
0824     if (flag_reference) {
0825         read_reference(ref_file);
0826         fclose(ref_file);
0827     }
0828 
0829     yyparse();
0830 
0831     if (flag_dump_types && visited_symbols) {
0832         while (visited_symbols != (struct symbol *)-1L) {
0833             struct symbol *sym = visited_symbols;
0834 
0835             if (sym->is_override)
0836                 fputs("override ", dumpfile);
0837             if (symbol_types[sym->type].n) {
0838                 putc(symbol_types[sym->type].n, dumpfile);
0839                 putc('#', dumpfile);
0840             }
0841             fputs(sym->name, dumpfile);
0842             putc(' ', dumpfile);
0843             if (sym->is_extern)
0844                 fputs("extern ", dumpfile);
0845             print_list(dumpfile, sym->defn);
0846             putc('\n', dumpfile);
0847 
0848             visited_symbols = sym->visited;
0849             sym->visited = NULL;
0850         }
0851     }
0852 
0853     if (flag_debug) {
0854         fprintf(debugfile, "Hash table occupancy %d/%d = %g\n",
0855             nsyms, HASH_BUCKETS,
0856             (double)nsyms / (double)HASH_BUCKETS);
0857     }
0858 
0859     if (dumpfile)
0860         fclose(dumpfile);
0861 
0862     return errors != 0;
0863 }