1 /* Generate kernel symbol version hashes.
2 Copyright 1996, 1997 Linux International.
4 New implementation contributed by Richard Henderson <rth@tamu.edu>
5 Based on original work by Bjorn Ekwall <bj0rn@blox.se>
7 This file was part of the Linux modutils 2.4.22: moved back into the
8 kernel sources by Rusty Russell/Kai Germaschewski.
10 This program is free software; you can redistribute it and/or modify it
11 under the terms of the GNU General Public License as published by the
12 Free Software Foundation; either version 2 of the License, or (at your
13 option) any later version.
15 This program is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software Foundation,
22 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
30 #ifdef __GNU_LIBRARY__
32 #endif /* __GNU_LIBRARY__ */
35 /*----------------------------------------------------------------------*/
37 #define HASH_BUCKETS 4096
39 static struct symbol *symtab[HASH_BUCKETS];
40 static FILE *debugfile;
45 static int flag_debug, flag_dump_defs, flag_reference, flag_dump_types,
46 flag_preserve, flag_warnings;
47 static const char *arch = "";
48 static const char *mod_prefix = "";
53 static struct symbol *expansion_trail;
54 static struct symbol *visited_symbols;
56 static const char *const symbol_type_name[] = {
57 "normal", "typedef", "enum", "struct", "union"
60 static int equal_list(struct string_list *a, struct string_list *b);
61 static void print_list(FILE * f, struct string_list *list);
62 static void print_location(void);
63 static void print_type_name(enum symbol_type type, const char *name);
65 /*----------------------------------------------------------------------*/
67 static const unsigned int crctab32[] = {
68 0x00000000U, 0x77073096U, 0xee0e612cU, 0x990951baU, 0x076dc419U,
69 0x706af48fU, 0xe963a535U, 0x9e6495a3U, 0x0edb8832U, 0x79dcb8a4U,
70 0xe0d5e91eU, 0x97d2d988U, 0x09b64c2bU, 0x7eb17cbdU, 0xe7b82d07U,
71 0x90bf1d91U, 0x1db71064U, 0x6ab020f2U, 0xf3b97148U, 0x84be41deU,
72 0x1adad47dU, 0x6ddde4ebU, 0xf4d4b551U, 0x83d385c7U, 0x136c9856U,
73 0x646ba8c0U, 0xfd62f97aU, 0x8a65c9ecU, 0x14015c4fU, 0x63066cd9U,
74 0xfa0f3d63U, 0x8d080df5U, 0x3b6e20c8U, 0x4c69105eU, 0xd56041e4U,
75 0xa2677172U, 0x3c03e4d1U, 0x4b04d447U, 0xd20d85fdU, 0xa50ab56bU,
76 0x35b5a8faU, 0x42b2986cU, 0xdbbbc9d6U, 0xacbcf940U, 0x32d86ce3U,
77 0x45df5c75U, 0xdcd60dcfU, 0xabd13d59U, 0x26d930acU, 0x51de003aU,
78 0xc8d75180U, 0xbfd06116U, 0x21b4f4b5U, 0x56b3c423U, 0xcfba9599U,
79 0xb8bda50fU, 0x2802b89eU, 0x5f058808U, 0xc60cd9b2U, 0xb10be924U,
80 0x2f6f7c87U, 0x58684c11U, 0xc1611dabU, 0xb6662d3dU, 0x76dc4190U,
81 0x01db7106U, 0x98d220bcU, 0xefd5102aU, 0x71b18589U, 0x06b6b51fU,
82 0x9fbfe4a5U, 0xe8b8d433U, 0x7807c9a2U, 0x0f00f934U, 0x9609a88eU,
83 0xe10e9818U, 0x7f6a0dbbU, 0x086d3d2dU, 0x91646c97U, 0xe6635c01U,
84 0x6b6b51f4U, 0x1c6c6162U, 0x856530d8U, 0xf262004eU, 0x6c0695edU,
85 0x1b01a57bU, 0x8208f4c1U, 0xf50fc457U, 0x65b0d9c6U, 0x12b7e950U,
86 0x8bbeb8eaU, 0xfcb9887cU, 0x62dd1ddfU, 0x15da2d49U, 0x8cd37cf3U,
87 0xfbd44c65U, 0x4db26158U, 0x3ab551ceU, 0xa3bc0074U, 0xd4bb30e2U,
88 0x4adfa541U, 0x3dd895d7U, 0xa4d1c46dU, 0xd3d6f4fbU, 0x4369e96aU,
89 0x346ed9fcU, 0xad678846U, 0xda60b8d0U, 0x44042d73U, 0x33031de5U,
90 0xaa0a4c5fU, 0xdd0d7cc9U, 0x5005713cU, 0x270241aaU, 0xbe0b1010U,
91 0xc90c2086U, 0x5768b525U, 0x206f85b3U, 0xb966d409U, 0xce61e49fU,
92 0x5edef90eU, 0x29d9c998U, 0xb0d09822U, 0xc7d7a8b4U, 0x59b33d17U,
93 0x2eb40d81U, 0xb7bd5c3bU, 0xc0ba6cadU, 0xedb88320U, 0x9abfb3b6U,
94 0x03b6e20cU, 0x74b1d29aU, 0xead54739U, 0x9dd277afU, 0x04db2615U,
95 0x73dc1683U, 0xe3630b12U, 0x94643b84U, 0x0d6d6a3eU, 0x7a6a5aa8U,
96 0xe40ecf0bU, 0x9309ff9dU, 0x0a00ae27U, 0x7d079eb1U, 0xf00f9344U,
97 0x8708a3d2U, 0x1e01f268U, 0x6906c2feU, 0xf762575dU, 0x806567cbU,
98 0x196c3671U, 0x6e6b06e7U, 0xfed41b76U, 0x89d32be0U, 0x10da7a5aU,
99 0x67dd4accU, 0xf9b9df6fU, 0x8ebeeff9U, 0x17b7be43U, 0x60b08ed5U,
100 0xd6d6a3e8U, 0xa1d1937eU, 0x38d8c2c4U, 0x4fdff252U, 0xd1bb67f1U,
101 0xa6bc5767U, 0x3fb506ddU, 0x48b2364bU, 0xd80d2bdaU, 0xaf0a1b4cU,
102 0x36034af6U, 0x41047a60U, 0xdf60efc3U, 0xa867df55U, 0x316e8eefU,
103 0x4669be79U, 0xcb61b38cU, 0xbc66831aU, 0x256fd2a0U, 0x5268e236U,
104 0xcc0c7795U, 0xbb0b4703U, 0x220216b9U, 0x5505262fU, 0xc5ba3bbeU,
105 0xb2bd0b28U, 0x2bb45a92U, 0x5cb36a04U, 0xc2d7ffa7U, 0xb5d0cf31U,
106 0x2cd99e8bU, 0x5bdeae1dU, 0x9b64c2b0U, 0xec63f226U, 0x756aa39cU,
107 0x026d930aU, 0x9c0906a9U, 0xeb0e363fU, 0x72076785U, 0x05005713U,
108 0x95bf4a82U, 0xe2b87a14U, 0x7bb12baeU, 0x0cb61b38U, 0x92d28e9bU,
109 0xe5d5be0dU, 0x7cdcefb7U, 0x0bdbdf21U, 0x86d3d2d4U, 0xf1d4e242U,
110 0x68ddb3f8U, 0x1fda836eU, 0x81be16cdU, 0xf6b9265bU, 0x6fb077e1U,
111 0x18b74777U, 0x88085ae6U, 0xff0f6a70U, 0x66063bcaU, 0x11010b5cU,
112 0x8f659effU, 0xf862ae69U, 0x616bffd3U, 0x166ccf45U, 0xa00ae278U,
113 0xd70dd2eeU, 0x4e048354U, 0x3903b3c2U, 0xa7672661U, 0xd06016f7U,
114 0x4969474dU, 0x3e6e77dbU, 0xaed16a4aU, 0xd9d65adcU, 0x40df0b66U,
115 0x37d83bf0U, 0xa9bcae53U, 0xdebb9ec5U, 0x47b2cf7fU, 0x30b5ffe9U,
116 0xbdbdf21cU, 0xcabac28aU, 0x53b39330U, 0x24b4a3a6U, 0xbad03605U,
117 0xcdd70693U, 0x54de5729U, 0x23d967bfU, 0xb3667a2eU, 0xc4614ab8U,
118 0x5d681b02U, 0x2a6f2b94U, 0xb40bbe37U, 0xc30c8ea1U, 0x5a05df1bU,
122 static unsigned long partial_crc32_one(unsigned char c, unsigned long crc)
124 return crctab32[(crc ^ c) & 0xff] ^ (crc >> 8);
127 static unsigned long partial_crc32(const char *s, unsigned long crc)
130 crc = partial_crc32_one(*s++, crc);
134 static unsigned long crc32(const char *s)
136 return partial_crc32(s, 0xffffffff) ^ 0xffffffff;
139 /*----------------------------------------------------------------------*/
141 static enum symbol_type map_to_ns(enum symbol_type t)
143 if (t == SYM_TYPEDEF)
145 else if (t == SYM_UNION)
150 struct symbol *find_symbol(const char *name, enum symbol_type ns)
152 unsigned long h = crc32(name) % HASH_BUCKETS;
155 for (sym = symtab[h]; sym; sym = sym->hash_next)
156 if (map_to_ns(sym->type) == map_to_ns(ns) &&
157 strcmp(name, sym->name) == 0 &&
164 static int is_unknown_symbol(struct symbol *sym)
166 struct string_list *defn;
168 return ((sym->type == SYM_STRUCT ||
169 sym->type == SYM_UNION ||
170 sym->type == SYM_ENUM) &&
171 (defn = sym->defn) && defn->tag == SYM_NORMAL &&
172 strcmp(defn->string, "}") == 0 &&
173 (defn = defn->next) && defn->tag == SYM_NORMAL &&
174 strcmp(defn->string, "UNKNOWN") == 0 &&
175 (defn = defn->next) && defn->tag == SYM_NORMAL &&
176 strcmp(defn->string, "{") == 0);
179 static struct symbol *__add_symbol(const char *name, enum symbol_type type,
180 struct string_list *defn, int is_extern,
183 unsigned long h = crc32(name) % HASH_BUCKETS;
185 enum symbol_status status = STATUS_UNCHANGED;
187 for (sym = symtab[h]; sym; sym = sym->hash_next) {
188 if (map_to_ns(sym->type) == map_to_ns(type) &&
189 strcmp(name, sym->name) == 0) {
192 else if (sym->type == type &&
193 equal_list(sym->defn, defn)) {
194 if (!sym->is_declared && sym->is_override) {
196 print_type_name(type, name);
197 fprintf(stderr, " modversion is "
200 sym->is_declared = 1;
202 } else if (!sym->is_declared) {
203 if (sym->is_override && flag_preserve) {
205 fprintf(stderr, "ignoring ");
206 print_type_name(type, name);
207 fprintf(stderr, " modversion change\n");
208 sym->is_declared = 1;
211 status = is_unknown_symbol(sym) ?
212 STATUS_DEFINED : STATUS_MODIFIED;
215 error_with_pos("redefinition of %s", name);
223 struct symbol **psym;
225 for (psym = &symtab[h]; *psym; psym = &(*psym)->hash_next) {
227 *psym = sym->hash_next;
234 sym = xmalloc(sizeof(*sym));
238 sym->expansion_trail = NULL;
240 sym->is_extern = is_extern;
242 sym->hash_next = symtab[h];
245 sym->is_declared = !is_reference;
246 sym->status = status;
247 sym->is_override = 0;
250 fprintf(debugfile, "Defn for %s %s == <",
251 symbol_type_name[type], name);
253 fputs("extern ", debugfile);
254 print_list(debugfile, defn);
255 fputs(">\n", debugfile);
262 struct symbol *add_symbol(const char *name, enum symbol_type type,
263 struct string_list *defn, int is_extern)
265 return __add_symbol(name, type, defn, is_extern, 0);
268 static struct symbol *add_reference_symbol(const char *name, enum symbol_type type,
269 struct string_list *defn, int is_extern)
271 return __add_symbol(name, type, defn, is_extern, 1);
274 /*----------------------------------------------------------------------*/
276 void free_node(struct string_list *node)
282 void free_list(struct string_list *s, struct string_list *e)
285 struct string_list *next = s->next;
291 struct string_list *copy_node(struct string_list *node)
293 struct string_list *newnode;
295 newnode = xmalloc(sizeof(*newnode));
296 newnode->string = xstrdup(node->string);
297 newnode->tag = node->tag;
302 static int equal_list(struct string_list *a, struct string_list *b)
305 if (a->tag != b->tag || strcmp(a->string, b->string))
314 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
316 static struct string_list *read_node(FILE *f)
319 struct string_list node = {
324 while ((c = fgetc(f)) != EOF) {
326 if (node.string == buffer)
329 } else if (c == '\n') {
330 if (node.string == buffer)
335 if (node.string >= buffer + sizeof(buffer) - 1) {
336 fprintf(stderr, "Token too long\n");
341 if (node.string == buffer)
344 node.string = buffer;
346 if (node.string[1] == '#') {
349 for (n = 0; n < ARRAY_SIZE(symbol_type_name); n++) {
350 if (node.string[0] == symbol_type_name[n][0]) {
353 return copy_node(&node);
356 fprintf(stderr, "Unknown type %c\n", node.string[0]);
359 return copy_node(&node);
362 static void read_reference(FILE *f)
365 struct string_list *defn = NULL;
366 struct string_list *sym, *def;
367 int is_extern = 0, is_override = 0;
368 struct symbol *subsym;
371 if (sym && sym->tag == SYM_NORMAL &&
372 !strcmp(sym->string, "override")) {
380 if (def && def->tag == SYM_NORMAL &&
381 !strcmp(def->string, "extern")) {
391 subsym = add_reference_symbol(xstrdup(sym->string), sym->tag,
393 subsym->is_override = is_override;
398 static void print_node(FILE * f, struct string_list *list)
400 if (list->tag != SYM_NORMAL) {
401 putc(symbol_type_name[list->tag][0], f);
404 fputs(list->string, f);
407 static void print_list(FILE * f, struct string_list *list)
409 struct string_list **e, **b;
410 struct string_list *tmp, **tmp2;
419 while ((tmp = tmp->next) != NULL)
422 b = alloca(elem * sizeof(*e));
427 while ((list = list->next) != NULL)
436 static unsigned long expand_and_crc_sym(struct symbol *sym, unsigned long crc)
438 struct string_list *list = sym->defn;
439 struct string_list **e, **b;
440 struct string_list *tmp, **tmp2;
447 while ((tmp = tmp->next) != NULL)
450 b = alloca(elem * sizeof(*e));
455 while ((list = list->next) != NULL)
459 struct string_list *cur;
460 struct symbol *subsym;
466 fprintf(debugfile, "%s ", cur->string);
467 crc = partial_crc32(cur->string, crc);
468 crc = partial_crc32_one(' ', crc);
472 subsym = find_symbol(cur->string, cur->tag);
473 /* FIXME: Bad reference files can segfault here. */
474 if (subsym->expansion_trail) {
476 fprintf(debugfile, "%s ", cur->string);
477 crc = partial_crc32(cur->string, crc);
478 crc = partial_crc32_one(' ', crc);
480 subsym->expansion_trail = expansion_trail;
481 expansion_trail = subsym;
482 crc = expand_and_crc_sym(subsym, crc);
489 subsym = find_symbol(cur->string, cur->tag);
491 struct string_list *n, *t = NULL;
493 error_with_pos("expand undefined %s %s",
494 symbol_type_name[cur->tag],
497 n = xmalloc(sizeof(*n));
498 n->string = xstrdup(symbol_type_name[cur->tag]);
503 n = xmalloc(sizeof(*n));
504 n->string = xstrdup(cur->string);
509 n = xmalloc(sizeof(*n));
510 n->string = xstrdup("{");
515 n = xmalloc(sizeof(*n));
516 n->string = xstrdup("UNKNOWN");
521 n = xmalloc(sizeof(*n));
522 n->string = xstrdup("}");
528 add_symbol(cur->string, cur->tag, n, 0);
530 if (subsym->expansion_trail) {
531 if (flag_dump_defs) {
532 fprintf(debugfile, "%s %s ",
533 symbol_type_name[cur->tag],
537 crc = partial_crc32(symbol_type_name[cur->tag],
539 crc = partial_crc32_one(' ', crc);
540 crc = partial_crc32(cur->string, crc);
541 crc = partial_crc32_one(' ', crc);
543 subsym->expansion_trail = expansion_trail;
544 expansion_trail = subsym;
545 crc = expand_and_crc_sym(subsym, crc);
552 static struct symbol **end = &visited_symbols;
557 sym->visited = (struct symbol *)-1L;
564 void export_symbol(const char *name)
568 sym = find_symbol(name, SYM_NORMAL);
570 error_with_pos("export undefined symbol %s", name);
576 fprintf(debugfile, "Export %s == <", name);
578 expansion_trail = (struct symbol *)-1L;
580 sym->expansion_trail = expansion_trail;
581 expansion_trail = sym;
582 crc = expand_and_crc_sym(sym, 0xffffffff) ^ 0xffffffff;
584 sym = expansion_trail;
585 while (sym != (struct symbol *)-1L) {
586 struct symbol *n = sym->expansion_trail;
588 if (sym->status != STATUS_UNCHANGED) {
591 fprintf(stderr, "%s: %s: modversion "
592 "changed because of changes "
593 "in ", flag_preserve ? "error" :
596 fprintf(stderr, ", ");
597 print_type_name(sym->type, sym->name);
598 if (sym->status == STATUS_DEFINED)
599 fprintf(stderr, " (became defined)");
604 sym->expansion_trail = 0;
608 fprintf(stderr, "\n");
611 fputs(">\n", debugfile);
613 /* Used as a linker script. */
614 printf("%s__crc_%s = 0x%08lx ;\n", mod_prefix, name, crc);
618 /*----------------------------------------------------------------------*/
620 static void print_location(void)
622 fprintf(stderr, "%s:%d: ", cur_filename ? : "<stdin>", cur_line);
625 static void print_type_name(enum symbol_type type, const char *name)
627 if (type != SYM_NORMAL)
628 fprintf(stderr, "%s %s", symbol_type_name[type], name);
630 fprintf(stderr, "%s", name);
633 void error_with_pos(const char *fmt, ...)
641 vfprintf(stderr, fmt, args);
649 static void genksyms_usage(void)
651 fputs("Usage:\n" "genksyms [-adDTwqhV] > /path/to/.tmp_obj.ver\n" "\n"
652 #ifdef __GNU_LIBRARY__
653 " -a, --arch Select architecture\n"
654 " -d, --debug Increment the debug level (repeatable)\n"
655 " -D, --dump Dump expanded symbol defs (for debugging only)\n"
656 " -r, --reference file Read reference symbols from a file\n"
657 " -T, --dump-types file Dump expanded types into file\n"
658 " -p, --preserve Preserve reference modversions or fail\n"
659 " -w, --warnings Enable warnings\n"
660 " -q, --quiet Disable warnings (default)\n"
661 " -h, --help Print this message\n"
662 " -V, --version Print the release version\n"
663 #else /* __GNU_LIBRARY__ */
664 " -a Select architecture\n"
665 " -d Increment the debug level (repeatable)\n"
666 " -D Dump expanded symbol defs (for debugging only)\n"
667 " -r file Read reference symbols from a file\n"
668 " -T file Dump expanded types into file\n"
669 " -p Preserve reference modversions or fail\n"
670 " -w Enable warnings\n"
671 " -q Disable warnings (default)\n"
672 " -h Print this message\n"
673 " -V Print the release version\n"
674 #endif /* __GNU_LIBRARY__ */
678 int main(int argc, char **argv)
680 FILE *dumpfile = NULL, *ref_file = NULL;
683 #ifdef __GNU_LIBRARY__
684 struct option long_opts[] = {
686 {"debug", 0, 0, 'd'},
687 {"warnings", 0, 0, 'w'},
688 {"quiet", 0, 0, 'q'},
690 {"reference", 1, 0, 'r'},
691 {"dump-types", 1, 0, 'T'},
692 {"preserve", 0, 0, 'p'},
693 {"version", 0, 0, 'V'},
698 while ((o = getopt_long(argc, argv, "a:dwqVDr:T:ph",
699 &long_opts[0], NULL)) != EOF)
700 #else /* __GNU_LIBRARY__ */
701 while ((o = getopt(argc, argv, "a:dwqVDr:T:ph")) != EOF)
702 #endif /* __GNU_LIBRARY__ */
717 fputs("genksyms version 2.5.60\n", stderr);
724 ref_file = fopen(optarg, "r");
732 dumpfile = fopen(optarg, "w");
748 if ((strcmp(arch, "h8300") == 0) || (strcmp(arch, "blackfin") == 0))
752 extern int yy_flex_debug;
754 yydebug = (flag_debug > 1);
755 yy_flex_debug = (flag_debug > 2);
758 /* setlinebuf(debugfile); */
761 if (flag_reference) {
762 read_reference(ref_file);
768 if (flag_dump_types && visited_symbols) {
769 while (visited_symbols != (struct symbol *)-1L) {
770 struct symbol *sym = visited_symbols;
772 if (sym->is_override)
773 fputs("override ", dumpfile);
774 if (sym->type != SYM_NORMAL) {
775 putc(symbol_type_name[sym->type][0], dumpfile);
778 fputs(sym->name, dumpfile);
781 fputs("extern ", dumpfile);
782 print_list(dumpfile, sym->defn);
783 putc('\n', dumpfile);
785 visited_symbols = sym->visited;
791 fprintf(debugfile, "Hash table occupancy %d/%d = %g\n",
793 (double)nsyms / (double)HASH_BUCKETS);