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;
60 [SYM_NORMAL] = { 0, NULL},
61 [SYM_TYPEDEF] = {'t', "typedef"},
62 [SYM_ENUM] = {'e', "enum"},
63 [SYM_STRUCT] = {'s', "struct"},
64 [SYM_UNION] = {'u', "union"},
67 static int equal_list(struct string_list *a, struct string_list *b);
68 static void print_list(FILE * f, struct string_list *list);
69 static struct string_list *concat_list(struct string_list *start, ...);
70 static struct string_list *mk_node(const char *string);
71 static void print_location(void);
72 static void print_type_name(enum symbol_type type, const char *name);
74 /*----------------------------------------------------------------------*/
76 static const unsigned int crctab32[] = {
77 0x00000000U, 0x77073096U, 0xee0e612cU, 0x990951baU, 0x076dc419U,
78 0x706af48fU, 0xe963a535U, 0x9e6495a3U, 0x0edb8832U, 0x79dcb8a4U,
79 0xe0d5e91eU, 0x97d2d988U, 0x09b64c2bU, 0x7eb17cbdU, 0xe7b82d07U,
80 0x90bf1d91U, 0x1db71064U, 0x6ab020f2U, 0xf3b97148U, 0x84be41deU,
81 0x1adad47dU, 0x6ddde4ebU, 0xf4d4b551U, 0x83d385c7U, 0x136c9856U,
82 0x646ba8c0U, 0xfd62f97aU, 0x8a65c9ecU, 0x14015c4fU, 0x63066cd9U,
83 0xfa0f3d63U, 0x8d080df5U, 0x3b6e20c8U, 0x4c69105eU, 0xd56041e4U,
84 0xa2677172U, 0x3c03e4d1U, 0x4b04d447U, 0xd20d85fdU, 0xa50ab56bU,
85 0x35b5a8faU, 0x42b2986cU, 0xdbbbc9d6U, 0xacbcf940U, 0x32d86ce3U,
86 0x45df5c75U, 0xdcd60dcfU, 0xabd13d59U, 0x26d930acU, 0x51de003aU,
87 0xc8d75180U, 0xbfd06116U, 0x21b4f4b5U, 0x56b3c423U, 0xcfba9599U,
88 0xb8bda50fU, 0x2802b89eU, 0x5f058808U, 0xc60cd9b2U, 0xb10be924U,
89 0x2f6f7c87U, 0x58684c11U, 0xc1611dabU, 0xb6662d3dU, 0x76dc4190U,
90 0x01db7106U, 0x98d220bcU, 0xefd5102aU, 0x71b18589U, 0x06b6b51fU,
91 0x9fbfe4a5U, 0xe8b8d433U, 0x7807c9a2U, 0x0f00f934U, 0x9609a88eU,
92 0xe10e9818U, 0x7f6a0dbbU, 0x086d3d2dU, 0x91646c97U, 0xe6635c01U,
93 0x6b6b51f4U, 0x1c6c6162U, 0x856530d8U, 0xf262004eU, 0x6c0695edU,
94 0x1b01a57bU, 0x8208f4c1U, 0xf50fc457U, 0x65b0d9c6U, 0x12b7e950U,
95 0x8bbeb8eaU, 0xfcb9887cU, 0x62dd1ddfU, 0x15da2d49U, 0x8cd37cf3U,
96 0xfbd44c65U, 0x4db26158U, 0x3ab551ceU, 0xa3bc0074U, 0xd4bb30e2U,
97 0x4adfa541U, 0x3dd895d7U, 0xa4d1c46dU, 0xd3d6f4fbU, 0x4369e96aU,
98 0x346ed9fcU, 0xad678846U, 0xda60b8d0U, 0x44042d73U, 0x33031de5U,
99 0xaa0a4c5fU, 0xdd0d7cc9U, 0x5005713cU, 0x270241aaU, 0xbe0b1010U,
100 0xc90c2086U, 0x5768b525U, 0x206f85b3U, 0xb966d409U, 0xce61e49fU,
101 0x5edef90eU, 0x29d9c998U, 0xb0d09822U, 0xc7d7a8b4U, 0x59b33d17U,
102 0x2eb40d81U, 0xb7bd5c3bU, 0xc0ba6cadU, 0xedb88320U, 0x9abfb3b6U,
103 0x03b6e20cU, 0x74b1d29aU, 0xead54739U, 0x9dd277afU, 0x04db2615U,
104 0x73dc1683U, 0xe3630b12U, 0x94643b84U, 0x0d6d6a3eU, 0x7a6a5aa8U,
105 0xe40ecf0bU, 0x9309ff9dU, 0x0a00ae27U, 0x7d079eb1U, 0xf00f9344U,
106 0x8708a3d2U, 0x1e01f268U, 0x6906c2feU, 0xf762575dU, 0x806567cbU,
107 0x196c3671U, 0x6e6b06e7U, 0xfed41b76U, 0x89d32be0U, 0x10da7a5aU,
108 0x67dd4accU, 0xf9b9df6fU, 0x8ebeeff9U, 0x17b7be43U, 0x60b08ed5U,
109 0xd6d6a3e8U, 0xa1d1937eU, 0x38d8c2c4U, 0x4fdff252U, 0xd1bb67f1U,
110 0xa6bc5767U, 0x3fb506ddU, 0x48b2364bU, 0xd80d2bdaU, 0xaf0a1b4cU,
111 0x36034af6U, 0x41047a60U, 0xdf60efc3U, 0xa867df55U, 0x316e8eefU,
112 0x4669be79U, 0xcb61b38cU, 0xbc66831aU, 0x256fd2a0U, 0x5268e236U,
113 0xcc0c7795U, 0xbb0b4703U, 0x220216b9U, 0x5505262fU, 0xc5ba3bbeU,
114 0xb2bd0b28U, 0x2bb45a92U, 0x5cb36a04U, 0xc2d7ffa7U, 0xb5d0cf31U,
115 0x2cd99e8bU, 0x5bdeae1dU, 0x9b64c2b0U, 0xec63f226U, 0x756aa39cU,
116 0x026d930aU, 0x9c0906a9U, 0xeb0e363fU, 0x72076785U, 0x05005713U,
117 0x95bf4a82U, 0xe2b87a14U, 0x7bb12baeU, 0x0cb61b38U, 0x92d28e9bU,
118 0xe5d5be0dU, 0x7cdcefb7U, 0x0bdbdf21U, 0x86d3d2d4U, 0xf1d4e242U,
119 0x68ddb3f8U, 0x1fda836eU, 0x81be16cdU, 0xf6b9265bU, 0x6fb077e1U,
120 0x18b74777U, 0x88085ae6U, 0xff0f6a70U, 0x66063bcaU, 0x11010b5cU,
121 0x8f659effU, 0xf862ae69U, 0x616bffd3U, 0x166ccf45U, 0xa00ae278U,
122 0xd70dd2eeU, 0x4e048354U, 0x3903b3c2U, 0xa7672661U, 0xd06016f7U,
123 0x4969474dU, 0x3e6e77dbU, 0xaed16a4aU, 0xd9d65adcU, 0x40df0b66U,
124 0x37d83bf0U, 0xa9bcae53U, 0xdebb9ec5U, 0x47b2cf7fU, 0x30b5ffe9U,
125 0xbdbdf21cU, 0xcabac28aU, 0x53b39330U, 0x24b4a3a6U, 0xbad03605U,
126 0xcdd70693U, 0x54de5729U, 0x23d967bfU, 0xb3667a2eU, 0xc4614ab8U,
127 0x5d681b02U, 0x2a6f2b94U, 0xb40bbe37U, 0xc30c8ea1U, 0x5a05df1bU,
131 static unsigned long partial_crc32_one(unsigned char c, unsigned long crc)
133 return crctab32[(crc ^ c) & 0xff] ^ (crc >> 8);
136 static unsigned long partial_crc32(const char *s, unsigned long crc)
139 crc = partial_crc32_one(*s++, crc);
143 static unsigned long crc32(const char *s)
145 return partial_crc32(s, 0xffffffff) ^ 0xffffffff;
148 /*----------------------------------------------------------------------*/
150 static enum symbol_type map_to_ns(enum symbol_type t)
152 if (t == SYM_TYPEDEF)
154 else if (t == SYM_UNION)
159 struct symbol *find_symbol(const char *name, enum symbol_type ns, int exact)
161 unsigned long h = crc32(name) % HASH_BUCKETS;
164 for (sym = symtab[h]; sym; sym = sym->hash_next)
165 if (map_to_ns(sym->type) == map_to_ns(ns) &&
166 strcmp(name, sym->name) == 0 &&
170 if (exact && sym && sym->type != ns)
175 static int is_unknown_symbol(struct symbol *sym)
177 struct string_list *defn;
179 return ((sym->type == SYM_STRUCT ||
180 sym->type == SYM_UNION ||
181 sym->type == SYM_ENUM) &&
182 (defn = sym->defn) && defn->tag == SYM_NORMAL &&
183 strcmp(defn->string, "}") == 0 &&
184 (defn = defn->next) && defn->tag == SYM_NORMAL &&
185 strcmp(defn->string, "UNKNOWN") == 0 &&
186 (defn = defn->next) && defn->tag == SYM_NORMAL &&
187 strcmp(defn->string, "{") == 0);
190 static struct symbol *__add_symbol(const char *name, enum symbol_type type,
191 struct string_list *defn, int is_extern,
194 unsigned long h = crc32(name) % HASH_BUCKETS;
196 enum symbol_status status = STATUS_UNCHANGED;
198 for (sym = symtab[h]; sym; sym = sym->hash_next) {
199 if (map_to_ns(sym->type) == map_to_ns(type) &&
200 strcmp(name, sym->name) == 0) {
203 else if (sym->type == type &&
204 equal_list(sym->defn, defn)) {
205 if (!sym->is_declared && sym->is_override) {
207 print_type_name(type, name);
208 fprintf(stderr, " modversion is "
211 sym->is_declared = 1;
213 } else if (!sym->is_declared) {
214 if (sym->is_override && flag_preserve) {
216 fprintf(stderr, "ignoring ");
217 print_type_name(type, name);
218 fprintf(stderr, " modversion change\n");
219 sym->is_declared = 1;
222 status = is_unknown_symbol(sym) ?
223 STATUS_DEFINED : STATUS_MODIFIED;
226 error_with_pos("redefinition of %s", name);
234 struct symbol **psym;
236 for (psym = &symtab[h]; *psym; psym = &(*psym)->hash_next) {
238 *psym = sym->hash_next;
245 sym = xmalloc(sizeof(*sym));
249 sym->expansion_trail = NULL;
251 sym->is_extern = is_extern;
253 sym->hash_next = symtab[h];
256 sym->is_declared = !is_reference;
257 sym->status = status;
258 sym->is_override = 0;
261 if (symbol_types[type].name)
262 fprintf(debugfile, "Defn for %s %s == <",
263 symbol_types[type].name, name);
265 fprintf(debugfile, "Defn for type%d %s == <",
268 fputs("extern ", debugfile);
269 print_list(debugfile, defn);
270 fputs(">\n", debugfile);
277 struct symbol *add_symbol(const char *name, enum symbol_type type,
278 struct string_list *defn, int is_extern)
280 return __add_symbol(name, type, defn, is_extern, 0);
283 static struct symbol *add_reference_symbol(const char *name, enum symbol_type type,
284 struct string_list *defn, int is_extern)
286 return __add_symbol(name, type, defn, is_extern, 1);
289 /*----------------------------------------------------------------------*/
291 void free_node(struct string_list *node)
297 void free_list(struct string_list *s, struct string_list *e)
300 struct string_list *next = s->next;
306 static struct string_list *mk_node(const char *string)
308 struct string_list *newnode;
310 newnode = xmalloc(sizeof(*newnode));
311 newnode->string = xstrdup(string);
312 newnode->tag = SYM_NORMAL;
313 newnode->next = NULL;
318 static struct string_list *concat_list(struct string_list *start, ...)
321 struct string_list *n, *n2;
325 for (va_start(ap, start); (n = va_arg(ap, struct string_list *));) {
326 for (n2 = n; n2->next; n2 = n2->next)
335 struct string_list *copy_node(struct string_list *node)
337 struct string_list *newnode;
339 newnode = xmalloc(sizeof(*newnode));
340 newnode->string = xstrdup(node->string);
341 newnode->tag = node->tag;
346 static int equal_list(struct string_list *a, struct string_list *b)
349 if (a->tag != b->tag || strcmp(a->string, b->string))
358 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
360 static struct string_list *read_node(FILE *f)
363 struct string_list node = {
368 while ((c = fgetc(f)) != EOF) {
370 if (node.string == buffer)
373 } else if (c == '\n') {
374 if (node.string == buffer)
379 if (node.string >= buffer + sizeof(buffer) - 1) {
380 fprintf(stderr, "Token too long\n");
385 if (node.string == buffer)
388 node.string = buffer;
390 if (node.string[1] == '#') {
393 for (n = 0; n < ARRAY_SIZE(symbol_types); n++) {
394 if (node.string[0] == symbol_types[n].n) {
397 return copy_node(&node);
400 fprintf(stderr, "Unknown type %c\n", node.string[0]);
403 return copy_node(&node);
406 static void read_reference(FILE *f)
409 struct string_list *defn = NULL;
410 struct string_list *sym, *def;
411 int is_extern = 0, is_override = 0;
412 struct symbol *subsym;
415 if (sym && sym->tag == SYM_NORMAL &&
416 !strcmp(sym->string, "override")) {
424 if (def && def->tag == SYM_NORMAL &&
425 !strcmp(def->string, "extern")) {
435 subsym = add_reference_symbol(xstrdup(sym->string), sym->tag,
437 subsym->is_override = is_override;
442 static void print_node(FILE * f, struct string_list *list)
444 if (symbol_types[list->tag].n) {
445 putc(symbol_types[list->tag].n, f);
448 fputs(list->string, f);
451 static void print_list(FILE * f, struct string_list *list)
453 struct string_list **e, **b;
454 struct string_list *tmp, **tmp2;
463 while ((tmp = tmp->next) != NULL)
466 b = alloca(elem * sizeof(*e));
471 while ((list = list->next) != NULL)
480 static unsigned long expand_and_crc_sym(struct symbol *sym, unsigned long crc)
482 struct string_list *list = sym->defn;
483 struct string_list **e, **b;
484 struct string_list *tmp, **tmp2;
491 while ((tmp = tmp->next) != NULL)
494 b = alloca(elem * sizeof(*e));
499 while ((list = list->next) != NULL)
503 struct string_list *cur;
504 struct symbol *subsym;
510 fprintf(debugfile, "%s ", cur->string);
511 crc = partial_crc32(cur->string, crc);
512 crc = partial_crc32_one(' ', crc);
516 subsym = find_symbol(cur->string, cur->tag, 0);
517 /* FIXME: Bad reference files can segfault here. */
518 if (subsym->expansion_trail) {
520 fprintf(debugfile, "%s ", cur->string);
521 crc = partial_crc32(cur->string, crc);
522 crc = partial_crc32_one(' ', crc);
524 subsym->expansion_trail = expansion_trail;
525 expansion_trail = subsym;
526 crc = expand_and_crc_sym(subsym, crc);
533 subsym = find_symbol(cur->string, cur->tag, 0);
535 struct string_list *n;
537 error_with_pos("expand undefined %s %s",
538 symbol_types[cur->tag].name,
540 n = concat_list(mk_node
541 (symbol_types[cur->tag].name),
542 mk_node(cur->string),
547 add_symbol(cur->string, cur->tag, n, 0);
549 if (subsym->expansion_trail) {
550 if (flag_dump_defs) {
551 fprintf(debugfile, "%s %s ",
552 symbol_types[cur->tag].name,
556 crc = partial_crc32(symbol_types[cur->tag].name,
558 crc = partial_crc32_one(' ', crc);
559 crc = partial_crc32(cur->string, crc);
560 crc = partial_crc32_one(' ', crc);
562 subsym->expansion_trail = expansion_trail;
563 expansion_trail = subsym;
564 crc = expand_and_crc_sym(subsym, crc);
571 static struct symbol **end = &visited_symbols;
576 sym->visited = (struct symbol *)-1L;
583 void export_symbol(const char *name)
587 sym = find_symbol(name, SYM_NORMAL, 0);
589 error_with_pos("export undefined symbol %s", name);
595 fprintf(debugfile, "Export %s == <", name);
597 expansion_trail = (struct symbol *)-1L;
599 sym->expansion_trail = expansion_trail;
600 expansion_trail = sym;
601 crc = expand_and_crc_sym(sym, 0xffffffff) ^ 0xffffffff;
603 sym = expansion_trail;
604 while (sym != (struct symbol *)-1L) {
605 struct symbol *n = sym->expansion_trail;
607 if (sym->status != STATUS_UNCHANGED) {
610 fprintf(stderr, "%s: %s: modversion "
611 "changed because of changes "
612 "in ", flag_preserve ? "error" :
615 fprintf(stderr, ", ");
616 print_type_name(sym->type, sym->name);
617 if (sym->status == STATUS_DEFINED)
618 fprintf(stderr, " (became defined)");
623 sym->expansion_trail = 0;
627 fprintf(stderr, "\n");
630 fputs(">\n", debugfile);
632 /* Used as a linker script. */
633 printf("%s__crc_%s = 0x%08lx ;\n", mod_prefix, name, crc);
637 /*----------------------------------------------------------------------*/
639 static void print_location(void)
641 fprintf(stderr, "%s:%d: ", cur_filename ? : "<stdin>", cur_line);
644 static void print_type_name(enum symbol_type type, const char *name)
646 if (symbol_types[type].name)
647 fprintf(stderr, "%s %s", symbol_types[type].name, name);
649 fprintf(stderr, "%s", name);
652 void error_with_pos(const char *fmt, ...)
660 vfprintf(stderr, fmt, args);
668 static void genksyms_usage(void)
670 fputs("Usage:\n" "genksyms [-adDTwqhV] > /path/to/.tmp_obj.ver\n" "\n"
671 #ifdef __GNU_LIBRARY__
672 " -a, --arch Select architecture\n"
673 " -d, --debug Increment the debug level (repeatable)\n"
674 " -D, --dump Dump expanded symbol defs (for debugging only)\n"
675 " -r, --reference file Read reference symbols from a file\n"
676 " -T, --dump-types file Dump expanded types into file\n"
677 " -p, --preserve Preserve reference modversions or fail\n"
678 " -w, --warnings Enable warnings\n"
679 " -q, --quiet Disable warnings (default)\n"
680 " -h, --help Print this message\n"
681 " -V, --version Print the release version\n"
682 #else /* __GNU_LIBRARY__ */
683 " -a Select architecture\n"
684 " -d Increment the debug level (repeatable)\n"
685 " -D Dump expanded symbol defs (for debugging only)\n"
686 " -r file Read reference symbols from a file\n"
687 " -T file Dump expanded types into file\n"
688 " -p Preserve reference modversions or fail\n"
689 " -w Enable warnings\n"
690 " -q Disable warnings (default)\n"
691 " -h Print this message\n"
692 " -V Print the release version\n"
693 #endif /* __GNU_LIBRARY__ */
697 int main(int argc, char **argv)
699 FILE *dumpfile = NULL, *ref_file = NULL;
702 #ifdef __GNU_LIBRARY__
703 struct option long_opts[] = {
705 {"debug", 0, 0, 'd'},
706 {"warnings", 0, 0, 'w'},
707 {"quiet", 0, 0, 'q'},
709 {"reference", 1, 0, 'r'},
710 {"dump-types", 1, 0, 'T'},
711 {"preserve", 0, 0, 'p'},
712 {"version", 0, 0, 'V'},
717 while ((o = getopt_long(argc, argv, "a:dwqVDr:T:ph",
718 &long_opts[0], NULL)) != EOF)
719 #else /* __GNU_LIBRARY__ */
720 while ((o = getopt(argc, argv, "a:dwqVDr:T:ph")) != EOF)
721 #endif /* __GNU_LIBRARY__ */
736 fputs("genksyms version 2.5.60\n", stderr);
743 ref_file = fopen(optarg, "r");
751 dumpfile = fopen(optarg, "w");
767 if ((strcmp(arch, "h8300") == 0) || (strcmp(arch, "blackfin") == 0))
771 extern int yy_flex_debug;
773 yydebug = (flag_debug > 1);
774 yy_flex_debug = (flag_debug > 2);
777 /* setlinebuf(debugfile); */
780 if (flag_reference) {
781 read_reference(ref_file);
787 if (flag_dump_types && visited_symbols) {
788 while (visited_symbols != (struct symbol *)-1L) {
789 struct symbol *sym = visited_symbols;
791 if (sym->is_override)
792 fputs("override ", dumpfile);
793 if (symbol_types[sym->type].n) {
794 putc(symbol_types[sym->type].n, dumpfile);
797 fputs(sym->name, dumpfile);
800 fputs("extern ", dumpfile);
801 print_list(dumpfile, sym->defn);
802 putc('\n', dumpfile);
804 visited_symbols = sym->visited;
810 fprintf(debugfile, "Hash table occupancy %d/%d = %g\n",
812 (double)nsyms / (double)HASH_BUCKETS);