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;
43 char *cur_filename, *source_file;
46 static int flag_debug, flag_dump_defs, flag_reference, flag_dump_types,
47 flag_preserve, flag_warnings, flag_rel_crcs;
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"},
65 [SYM_ENUM_CONST] = {'E', "enum constant"},
68 static int equal_list(struct string_list *a, struct string_list *b);
69 static void print_list(FILE * f, struct string_list *list);
70 static struct string_list *concat_list(struct string_list *start, ...);
71 static struct string_list *mk_node(const char *string);
72 static void print_location(void);
73 static void print_type_name(enum symbol_type type, const char *name);
75 /*----------------------------------------------------------------------*/
77 static const unsigned int crctab32[] = {
78 0x00000000U, 0x77073096U, 0xee0e612cU, 0x990951baU, 0x076dc419U,
79 0x706af48fU, 0xe963a535U, 0x9e6495a3U, 0x0edb8832U, 0x79dcb8a4U,
80 0xe0d5e91eU, 0x97d2d988U, 0x09b64c2bU, 0x7eb17cbdU, 0xe7b82d07U,
81 0x90bf1d91U, 0x1db71064U, 0x6ab020f2U, 0xf3b97148U, 0x84be41deU,
82 0x1adad47dU, 0x6ddde4ebU, 0xf4d4b551U, 0x83d385c7U, 0x136c9856U,
83 0x646ba8c0U, 0xfd62f97aU, 0x8a65c9ecU, 0x14015c4fU, 0x63066cd9U,
84 0xfa0f3d63U, 0x8d080df5U, 0x3b6e20c8U, 0x4c69105eU, 0xd56041e4U,
85 0xa2677172U, 0x3c03e4d1U, 0x4b04d447U, 0xd20d85fdU, 0xa50ab56bU,
86 0x35b5a8faU, 0x42b2986cU, 0xdbbbc9d6U, 0xacbcf940U, 0x32d86ce3U,
87 0x45df5c75U, 0xdcd60dcfU, 0xabd13d59U, 0x26d930acU, 0x51de003aU,
88 0xc8d75180U, 0xbfd06116U, 0x21b4f4b5U, 0x56b3c423U, 0xcfba9599U,
89 0xb8bda50fU, 0x2802b89eU, 0x5f058808U, 0xc60cd9b2U, 0xb10be924U,
90 0x2f6f7c87U, 0x58684c11U, 0xc1611dabU, 0xb6662d3dU, 0x76dc4190U,
91 0x01db7106U, 0x98d220bcU, 0xefd5102aU, 0x71b18589U, 0x06b6b51fU,
92 0x9fbfe4a5U, 0xe8b8d433U, 0x7807c9a2U, 0x0f00f934U, 0x9609a88eU,
93 0xe10e9818U, 0x7f6a0dbbU, 0x086d3d2dU, 0x91646c97U, 0xe6635c01U,
94 0x6b6b51f4U, 0x1c6c6162U, 0x856530d8U, 0xf262004eU, 0x6c0695edU,
95 0x1b01a57bU, 0x8208f4c1U, 0xf50fc457U, 0x65b0d9c6U, 0x12b7e950U,
96 0x8bbeb8eaU, 0xfcb9887cU, 0x62dd1ddfU, 0x15da2d49U, 0x8cd37cf3U,
97 0xfbd44c65U, 0x4db26158U, 0x3ab551ceU, 0xa3bc0074U, 0xd4bb30e2U,
98 0x4adfa541U, 0x3dd895d7U, 0xa4d1c46dU, 0xd3d6f4fbU, 0x4369e96aU,
99 0x346ed9fcU, 0xad678846U, 0xda60b8d0U, 0x44042d73U, 0x33031de5U,
100 0xaa0a4c5fU, 0xdd0d7cc9U, 0x5005713cU, 0x270241aaU, 0xbe0b1010U,
101 0xc90c2086U, 0x5768b525U, 0x206f85b3U, 0xb966d409U, 0xce61e49fU,
102 0x5edef90eU, 0x29d9c998U, 0xb0d09822U, 0xc7d7a8b4U, 0x59b33d17U,
103 0x2eb40d81U, 0xb7bd5c3bU, 0xc0ba6cadU, 0xedb88320U, 0x9abfb3b6U,
104 0x03b6e20cU, 0x74b1d29aU, 0xead54739U, 0x9dd277afU, 0x04db2615U,
105 0x73dc1683U, 0xe3630b12U, 0x94643b84U, 0x0d6d6a3eU, 0x7a6a5aa8U,
106 0xe40ecf0bU, 0x9309ff9dU, 0x0a00ae27U, 0x7d079eb1U, 0xf00f9344U,
107 0x8708a3d2U, 0x1e01f268U, 0x6906c2feU, 0xf762575dU, 0x806567cbU,
108 0x196c3671U, 0x6e6b06e7U, 0xfed41b76U, 0x89d32be0U, 0x10da7a5aU,
109 0x67dd4accU, 0xf9b9df6fU, 0x8ebeeff9U, 0x17b7be43U, 0x60b08ed5U,
110 0xd6d6a3e8U, 0xa1d1937eU, 0x38d8c2c4U, 0x4fdff252U, 0xd1bb67f1U,
111 0xa6bc5767U, 0x3fb506ddU, 0x48b2364bU, 0xd80d2bdaU, 0xaf0a1b4cU,
112 0x36034af6U, 0x41047a60U, 0xdf60efc3U, 0xa867df55U, 0x316e8eefU,
113 0x4669be79U, 0xcb61b38cU, 0xbc66831aU, 0x256fd2a0U, 0x5268e236U,
114 0xcc0c7795U, 0xbb0b4703U, 0x220216b9U, 0x5505262fU, 0xc5ba3bbeU,
115 0xb2bd0b28U, 0x2bb45a92U, 0x5cb36a04U, 0xc2d7ffa7U, 0xb5d0cf31U,
116 0x2cd99e8bU, 0x5bdeae1dU, 0x9b64c2b0U, 0xec63f226U, 0x756aa39cU,
117 0x026d930aU, 0x9c0906a9U, 0xeb0e363fU, 0x72076785U, 0x05005713U,
118 0x95bf4a82U, 0xe2b87a14U, 0x7bb12baeU, 0x0cb61b38U, 0x92d28e9bU,
119 0xe5d5be0dU, 0x7cdcefb7U, 0x0bdbdf21U, 0x86d3d2d4U, 0xf1d4e242U,
120 0x68ddb3f8U, 0x1fda836eU, 0x81be16cdU, 0xf6b9265bU, 0x6fb077e1U,
121 0x18b74777U, 0x88085ae6U, 0xff0f6a70U, 0x66063bcaU, 0x11010b5cU,
122 0x8f659effU, 0xf862ae69U, 0x616bffd3U, 0x166ccf45U, 0xa00ae278U,
123 0xd70dd2eeU, 0x4e048354U, 0x3903b3c2U, 0xa7672661U, 0xd06016f7U,
124 0x4969474dU, 0x3e6e77dbU, 0xaed16a4aU, 0xd9d65adcU, 0x40df0b66U,
125 0x37d83bf0U, 0xa9bcae53U, 0xdebb9ec5U, 0x47b2cf7fU, 0x30b5ffe9U,
126 0xbdbdf21cU, 0xcabac28aU, 0x53b39330U, 0x24b4a3a6U, 0xbad03605U,
127 0xcdd70693U, 0x54de5729U, 0x23d967bfU, 0xb3667a2eU, 0xc4614ab8U,
128 0x5d681b02U, 0x2a6f2b94U, 0xb40bbe37U, 0xc30c8ea1U, 0x5a05df1bU,
132 static unsigned long partial_crc32_one(unsigned char c, unsigned long crc)
134 return crctab32[(crc ^ c) & 0xff] ^ (crc >> 8);
137 static unsigned long partial_crc32(const char *s, unsigned long crc)
140 crc = partial_crc32_one(*s++, crc);
144 static unsigned long crc32(const char *s)
146 return partial_crc32(s, 0xffffffff) ^ 0xffffffff;
149 /*----------------------------------------------------------------------*/
151 static enum symbol_type map_to_ns(enum symbol_type t)
166 struct symbol *find_symbol(const char *name, enum symbol_type ns, int exact)
168 unsigned long h = crc32(name) % HASH_BUCKETS;
171 for (sym = symtab[h]; sym; sym = sym->hash_next)
172 if (map_to_ns(sym->type) == map_to_ns(ns) &&
173 strcmp(name, sym->name) == 0 &&
177 if (exact && sym && sym->type != ns)
182 static int is_unknown_symbol(struct symbol *sym)
184 struct string_list *defn;
186 return ((sym->type == SYM_STRUCT ||
187 sym->type == SYM_UNION ||
188 sym->type == SYM_ENUM) &&
189 (defn = sym->defn) && defn->tag == SYM_NORMAL &&
190 strcmp(defn->string, "}") == 0 &&
191 (defn = defn->next) && defn->tag == SYM_NORMAL &&
192 strcmp(defn->string, "UNKNOWN") == 0 &&
193 (defn = defn->next) && defn->tag == SYM_NORMAL &&
194 strcmp(defn->string, "{") == 0);
197 static struct symbol *__add_symbol(const char *name, enum symbol_type type,
198 struct string_list *defn, int is_extern,
203 enum symbol_status status = STATUS_UNCHANGED;
204 /* The parser adds symbols in the order their declaration completes,
205 * so it is safe to store the value of the previous enum constant in
208 static int enum_counter;
209 static struct string_list *last_enum_expr;
211 if (type == SYM_ENUM_CONST) {
213 free_list(last_enum_expr, NULL);
214 last_enum_expr = copy_list_range(defn, NULL);
217 struct string_list *expr;
220 snprintf(buf, sizeof(buf), "%d", enum_counter++);
221 if (last_enum_expr) {
222 expr = copy_list_range(last_enum_expr, NULL);
223 defn = concat_list(mk_node("("),
232 } else if (type == SYM_ENUM) {
233 free_list(last_enum_expr, NULL);
234 last_enum_expr = NULL;
237 /* Anonymous enum definition, nothing more to do */
241 h = crc32(name) % HASH_BUCKETS;
242 for (sym = symtab[h]; sym; sym = sym->hash_next) {
243 if (map_to_ns(sym->type) == map_to_ns(type) &&
244 strcmp(name, sym->name) == 0) {
247 else if (sym->type == type &&
248 equal_list(sym->defn, defn)) {
249 if (!sym->is_declared && sym->is_override) {
251 print_type_name(type, name);
252 fprintf(stderr, " modversion is "
255 sym->is_declared = 1;
257 } else if (!sym->is_declared) {
258 if (sym->is_override && flag_preserve) {
260 fprintf(stderr, "ignoring ");
261 print_type_name(type, name);
262 fprintf(stderr, " modversion change\n");
263 sym->is_declared = 1;
266 status = is_unknown_symbol(sym) ?
267 STATUS_DEFINED : STATUS_MODIFIED;
270 error_with_pos("redefinition of %s", name);
278 struct symbol **psym;
280 for (psym = &symtab[h]; *psym; psym = &(*psym)->hash_next) {
282 *psym = sym->hash_next;
289 sym = xmalloc(sizeof(*sym));
293 sym->expansion_trail = NULL;
295 sym->is_extern = is_extern;
297 sym->hash_next = symtab[h];
300 sym->is_declared = !is_reference;
301 sym->status = status;
302 sym->is_override = 0;
305 if (symbol_types[type].name)
306 fprintf(debugfile, "Defn for %s %s == <",
307 symbol_types[type].name, name);
309 fprintf(debugfile, "Defn for type%d %s == <",
312 fputs("extern ", debugfile);
313 print_list(debugfile, defn);
314 fputs(">\n", debugfile);
321 struct symbol *add_symbol(const char *name, enum symbol_type type,
322 struct string_list *defn, int is_extern)
324 return __add_symbol(name, type, defn, is_extern, 0);
327 static struct symbol *add_reference_symbol(const char *name, enum symbol_type type,
328 struct string_list *defn, int is_extern)
330 return __add_symbol(name, type, defn, is_extern, 1);
333 /*----------------------------------------------------------------------*/
335 void free_node(struct string_list *node)
341 void free_list(struct string_list *s, struct string_list *e)
344 struct string_list *next = s->next;
350 static struct string_list *mk_node(const char *string)
352 struct string_list *newnode;
354 newnode = xmalloc(sizeof(*newnode));
355 newnode->string = xstrdup(string);
356 newnode->tag = SYM_NORMAL;
357 newnode->next = NULL;
362 static struct string_list *concat_list(struct string_list *start, ...)
365 struct string_list *n, *n2;
369 for (va_start(ap, start); (n = va_arg(ap, struct string_list *));) {
370 for (n2 = n; n2->next; n2 = n2->next)
379 struct string_list *copy_node(struct string_list *node)
381 struct string_list *newnode;
383 newnode = xmalloc(sizeof(*newnode));
384 newnode->string = xstrdup(node->string);
385 newnode->tag = node->tag;
390 struct string_list *copy_list_range(struct string_list *start,
391 struct string_list *end)
393 struct string_list *res, *n;
397 n = res = copy_node(start);
398 for (start = start->next; start != end; start = start->next) {
399 n->next = copy_node(start);
406 static int equal_list(struct string_list *a, struct string_list *b)
409 if (a->tag != b->tag || strcmp(a->string, b->string))
418 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
420 static struct string_list *read_node(FILE *f)
423 struct string_list node = {
426 int c, in_string = 0;
428 while ((c = fgetc(f)) != EOF) {
429 if (!in_string && c == ' ') {
430 if (node.string == buffer)
433 } else if (c == '"') {
434 in_string = !in_string;
435 } else if (c == '\n') {
436 if (node.string == buffer)
441 if (node.string >= buffer + sizeof(buffer) - 1) {
442 fprintf(stderr, "Token too long\n");
447 if (node.string == buffer)
450 node.string = buffer;
452 if (node.string[1] == '#') {
455 for (n = 0; n < ARRAY_SIZE(symbol_types); n++) {
456 if (node.string[0] == symbol_types[n].n) {
459 return copy_node(&node);
462 fprintf(stderr, "Unknown type %c\n", node.string[0]);
465 return copy_node(&node);
468 static void read_reference(FILE *f)
471 struct string_list *defn = NULL;
472 struct string_list *sym, *def;
473 int is_extern = 0, is_override = 0;
474 struct symbol *subsym;
477 if (sym && sym->tag == SYM_NORMAL &&
478 !strcmp(sym->string, "override")) {
486 if (def && def->tag == SYM_NORMAL &&
487 !strcmp(def->string, "extern")) {
497 subsym = add_reference_symbol(xstrdup(sym->string), sym->tag,
499 subsym->is_override = is_override;
504 static void print_node(FILE * f, struct string_list *list)
506 if (symbol_types[list->tag].n) {
507 putc(symbol_types[list->tag].n, f);
510 fputs(list->string, f);
513 static void print_list(FILE * f, struct string_list *list)
515 struct string_list **e, **b;
516 struct string_list *tmp, **tmp2;
525 while ((tmp = tmp->next) != NULL)
528 b = alloca(elem * sizeof(*e));
533 while ((list = list->next) != NULL)
542 static unsigned long expand_and_crc_sym(struct symbol *sym, unsigned long crc)
544 struct string_list *list = sym->defn;
545 struct string_list **e, **b;
546 struct string_list *tmp, **tmp2;
553 while ((tmp = tmp->next) != NULL)
556 b = alloca(elem * sizeof(*e));
561 while ((list = list->next) != NULL)
565 struct string_list *cur;
566 struct symbol *subsym;
572 fprintf(debugfile, "%s ", cur->string);
573 crc = partial_crc32(cur->string, crc);
574 crc = partial_crc32_one(' ', crc);
579 subsym = find_symbol(cur->string, cur->tag, 0);
580 /* FIXME: Bad reference files can segfault here. */
581 if (subsym->expansion_trail) {
583 fprintf(debugfile, "%s ", cur->string);
584 crc = partial_crc32(cur->string, crc);
585 crc = partial_crc32_one(' ', crc);
587 subsym->expansion_trail = expansion_trail;
588 expansion_trail = subsym;
589 crc = expand_and_crc_sym(subsym, crc);
596 subsym = find_symbol(cur->string, cur->tag, 0);
598 struct string_list *n;
600 error_with_pos("expand undefined %s %s",
601 symbol_types[cur->tag].name,
603 n = concat_list(mk_node
604 (symbol_types[cur->tag].name),
605 mk_node(cur->string),
610 add_symbol(cur->string, cur->tag, n, 0);
612 if (subsym->expansion_trail) {
613 if (flag_dump_defs) {
614 fprintf(debugfile, "%s %s ",
615 symbol_types[cur->tag].name,
619 crc = partial_crc32(symbol_types[cur->tag].name,
621 crc = partial_crc32_one(' ', crc);
622 crc = partial_crc32(cur->string, crc);
623 crc = partial_crc32_one(' ', crc);
625 subsym->expansion_trail = expansion_trail;
626 expansion_trail = subsym;
627 crc = expand_and_crc_sym(subsym, crc);
634 static struct symbol **end = &visited_symbols;
639 sym->visited = (struct symbol *)-1L;
646 void export_symbol(const char *name)
650 sym = find_symbol(name, SYM_NORMAL, 0);
652 error_with_pos("export undefined symbol %s", name);
658 fprintf(debugfile, "Export %s == <", name);
660 expansion_trail = (struct symbol *)-1L;
662 sym->expansion_trail = expansion_trail;
663 expansion_trail = sym;
664 crc = expand_and_crc_sym(sym, 0xffffffff) ^ 0xffffffff;
666 sym = expansion_trail;
667 while (sym != (struct symbol *)-1L) {
668 struct symbol *n = sym->expansion_trail;
670 if (sym->status != STATUS_UNCHANGED) {
673 fprintf(stderr, "%s: %s: modversion "
674 "changed because of changes "
675 "in ", flag_preserve ? "error" :
678 fprintf(stderr, ", ");
679 print_type_name(sym->type, sym->name);
680 if (sym->status == STATUS_DEFINED)
681 fprintf(stderr, " (became defined)");
686 sym->expansion_trail = 0;
690 fprintf(stderr, "\n");
693 fputs(">\n", debugfile);
695 /* Used as a linker script. */
696 printf(!flag_rel_crcs ? "%s__crc_%s = 0x%08lx;\n" :
697 "SECTIONS { .rodata : ALIGN(4) { "
698 "%s__crc_%s = .; LONG(0x%08lx); } }\n",
699 mod_prefix, name, crc);
703 /*----------------------------------------------------------------------*/
705 static void print_location(void)
707 fprintf(stderr, "%s:%d: ", cur_filename ? : "<stdin>", cur_line);
710 static void print_type_name(enum symbol_type type, const char *name)
712 if (symbol_types[type].name)
713 fprintf(stderr, "%s %s", symbol_types[type].name, name);
715 fprintf(stderr, "%s", name);
718 void error_with_pos(const char *fmt, ...)
726 vfprintf(stderr, fmt, args);
734 static void genksyms_usage(void)
736 fputs("Usage:\n" "genksyms [-adDTwqhVR] > /path/to/.tmp_obj.ver\n" "\n"
737 #ifdef __GNU_LIBRARY__
738 " -s, --symbol-prefix Select symbol prefix\n"
739 " -d, --debug Increment the debug level (repeatable)\n"
740 " -D, --dump Dump expanded symbol defs (for debugging only)\n"
741 " -r, --reference file Read reference symbols from a file\n"
742 " -T, --dump-types file Dump expanded types into file\n"
743 " -p, --preserve Preserve reference modversions or fail\n"
744 " -w, --warnings Enable warnings\n"
745 " -q, --quiet Disable warnings (default)\n"
746 " -h, --help Print this message\n"
747 " -V, --version Print the release version\n"
748 " -R, --relative-crc Emit section relative symbol CRCs\n"
749 #else /* __GNU_LIBRARY__ */
750 " -s Select symbol prefix\n"
751 " -d Increment the debug level (repeatable)\n"
752 " -D Dump expanded symbol defs (for debugging only)\n"
753 " -r file Read reference symbols from a file\n"
754 " -T file Dump expanded types into file\n"
755 " -p Preserve reference modversions or fail\n"
756 " -w Enable warnings\n"
757 " -q Disable warnings (default)\n"
758 " -h Print this message\n"
759 " -V Print the release version\n"
760 " -R Emit section relative symbol CRCs\n"
761 #endif /* __GNU_LIBRARY__ */
765 int main(int argc, char **argv)
767 FILE *dumpfile = NULL, *ref_file = NULL;
770 #ifdef __GNU_LIBRARY__
771 struct option long_opts[] = {
772 {"symbol-prefix", 1, 0, 's'},
773 {"debug", 0, 0, 'd'},
774 {"warnings", 0, 0, 'w'},
775 {"quiet", 0, 0, 'q'},
777 {"reference", 1, 0, 'r'},
778 {"dump-types", 1, 0, 'T'},
779 {"preserve", 0, 0, 'p'},
780 {"version", 0, 0, 'V'},
782 {"relative-crc", 0, 0, 'R'},
786 while ((o = getopt_long(argc, argv, "s:dwqVDr:T:phR",
787 &long_opts[0], NULL)) != EOF)
788 #else /* __GNU_LIBRARY__ */
789 while ((o = getopt(argc, argv, "s:dwqVDr:T:phR")) != EOF)
790 #endif /* __GNU_LIBRARY__ */
805 fputs("genksyms version 2.5.60\n", stderr);
812 ref_file = fopen(optarg, "r");
820 dumpfile = fopen(optarg, "w");
841 extern int yy_flex_debug;
843 yydebug = (flag_debug > 1);
844 yy_flex_debug = (flag_debug > 2);
847 /* setlinebuf(debugfile); */
850 if (flag_reference) {
851 read_reference(ref_file);
857 if (flag_dump_types && visited_symbols) {
858 while (visited_symbols != (struct symbol *)-1L) {
859 struct symbol *sym = visited_symbols;
861 if (sym->is_override)
862 fputs("override ", dumpfile);
863 if (symbol_types[sym->type].n) {
864 putc(symbol_types[sym->type].n, dumpfile);
867 fputs(sym->name, dumpfile);
870 fputs("extern ", dumpfile);
871 print_list(dumpfile, sym->defn);
872 putc('\n', dumpfile);
874 visited_symbols = sym->visited;
880 fprintf(debugfile, "Hash table occupancy %d/%d = %g\n",
882 (double)nsyms / (double)HASH_BUCKETS);