Merge tag 'pull-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
[linux-2.6-microblaze.git] / scripts / genksyms / genksyms.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* Generate kernel symbol version hashes.
3    Copyright 1996, 1997 Linux International.
4
5    New implementation contributed by Richard Henderson <rth@tamu.edu>
6    Based on original work by Bjorn Ekwall <bj0rn@blox.se>
7
8    This file was part of the Linux modutils 2.4.22: moved back into the
9    kernel sources by Rusty Russell/Kai Germaschewski.
10
11  */
12
13 #include <stdio.h>
14 #include <string.h>
15 #include <stdlib.h>
16 #include <unistd.h>
17 #include <assert.h>
18 #include <stdarg.h>
19 #ifdef __GNU_LIBRARY__
20 #include <getopt.h>
21 #endif                          /* __GNU_LIBRARY__ */
22
23 #include "genksyms.h"
24 /*----------------------------------------------------------------------*/
25
26 #define HASH_BUCKETS  4096
27
28 static struct symbol *symtab[HASH_BUCKETS];
29 static FILE *debugfile;
30
31 int cur_line = 1;
32 char *cur_filename;
33 int in_source_file;
34
35 static int flag_debug, flag_dump_defs, flag_reference, flag_dump_types,
36            flag_preserve, flag_warnings;
37
38 static int errors;
39 static int nsyms;
40
41 static struct symbol *expansion_trail;
42 static struct symbol *visited_symbols;
43
44 static const struct {
45         int n;
46         const char *name;
47 } symbol_types[] = {
48         [SYM_NORMAL]     = { 0, NULL},
49         [SYM_TYPEDEF]    = {'t', "typedef"},
50         [SYM_ENUM]       = {'e', "enum"},
51         [SYM_STRUCT]     = {'s', "struct"},
52         [SYM_UNION]      = {'u', "union"},
53         [SYM_ENUM_CONST] = {'E', "enum constant"},
54 };
55
56 static int equal_list(struct string_list *a, struct string_list *b);
57 static void print_list(FILE * f, struct string_list *list);
58 static struct string_list *concat_list(struct string_list *start, ...);
59 static struct string_list *mk_node(const char *string);
60 static void print_location(void);
61 static void print_type_name(enum symbol_type type, const char *name);
62
63 /*----------------------------------------------------------------------*/
64
65 static const unsigned int crctab32[] = {
66         0x00000000U, 0x77073096U, 0xee0e612cU, 0x990951baU, 0x076dc419U,
67         0x706af48fU, 0xe963a535U, 0x9e6495a3U, 0x0edb8832U, 0x79dcb8a4U,
68         0xe0d5e91eU, 0x97d2d988U, 0x09b64c2bU, 0x7eb17cbdU, 0xe7b82d07U,
69         0x90bf1d91U, 0x1db71064U, 0x6ab020f2U, 0xf3b97148U, 0x84be41deU,
70         0x1adad47dU, 0x6ddde4ebU, 0xf4d4b551U, 0x83d385c7U, 0x136c9856U,
71         0x646ba8c0U, 0xfd62f97aU, 0x8a65c9ecU, 0x14015c4fU, 0x63066cd9U,
72         0xfa0f3d63U, 0x8d080df5U, 0x3b6e20c8U, 0x4c69105eU, 0xd56041e4U,
73         0xa2677172U, 0x3c03e4d1U, 0x4b04d447U, 0xd20d85fdU, 0xa50ab56bU,
74         0x35b5a8faU, 0x42b2986cU, 0xdbbbc9d6U, 0xacbcf940U, 0x32d86ce3U,
75         0x45df5c75U, 0xdcd60dcfU, 0xabd13d59U, 0x26d930acU, 0x51de003aU,
76         0xc8d75180U, 0xbfd06116U, 0x21b4f4b5U, 0x56b3c423U, 0xcfba9599U,
77         0xb8bda50fU, 0x2802b89eU, 0x5f058808U, 0xc60cd9b2U, 0xb10be924U,
78         0x2f6f7c87U, 0x58684c11U, 0xc1611dabU, 0xb6662d3dU, 0x76dc4190U,
79         0x01db7106U, 0x98d220bcU, 0xefd5102aU, 0x71b18589U, 0x06b6b51fU,
80         0x9fbfe4a5U, 0xe8b8d433U, 0x7807c9a2U, 0x0f00f934U, 0x9609a88eU,
81         0xe10e9818U, 0x7f6a0dbbU, 0x086d3d2dU, 0x91646c97U, 0xe6635c01U,
82         0x6b6b51f4U, 0x1c6c6162U, 0x856530d8U, 0xf262004eU, 0x6c0695edU,
83         0x1b01a57bU, 0x8208f4c1U, 0xf50fc457U, 0x65b0d9c6U, 0x12b7e950U,
84         0x8bbeb8eaU, 0xfcb9887cU, 0x62dd1ddfU, 0x15da2d49U, 0x8cd37cf3U,
85         0xfbd44c65U, 0x4db26158U, 0x3ab551ceU, 0xa3bc0074U, 0xd4bb30e2U,
86         0x4adfa541U, 0x3dd895d7U, 0xa4d1c46dU, 0xd3d6f4fbU, 0x4369e96aU,
87         0x346ed9fcU, 0xad678846U, 0xda60b8d0U, 0x44042d73U, 0x33031de5U,
88         0xaa0a4c5fU, 0xdd0d7cc9U, 0x5005713cU, 0x270241aaU, 0xbe0b1010U,
89         0xc90c2086U, 0x5768b525U, 0x206f85b3U, 0xb966d409U, 0xce61e49fU,
90         0x5edef90eU, 0x29d9c998U, 0xb0d09822U, 0xc7d7a8b4U, 0x59b33d17U,
91         0x2eb40d81U, 0xb7bd5c3bU, 0xc0ba6cadU, 0xedb88320U, 0x9abfb3b6U,
92         0x03b6e20cU, 0x74b1d29aU, 0xead54739U, 0x9dd277afU, 0x04db2615U,
93         0x73dc1683U, 0xe3630b12U, 0x94643b84U, 0x0d6d6a3eU, 0x7a6a5aa8U,
94         0xe40ecf0bU, 0x9309ff9dU, 0x0a00ae27U, 0x7d079eb1U, 0xf00f9344U,
95         0x8708a3d2U, 0x1e01f268U, 0x6906c2feU, 0xf762575dU, 0x806567cbU,
96         0x196c3671U, 0x6e6b06e7U, 0xfed41b76U, 0x89d32be0U, 0x10da7a5aU,
97         0x67dd4accU, 0xf9b9df6fU, 0x8ebeeff9U, 0x17b7be43U, 0x60b08ed5U,
98         0xd6d6a3e8U, 0xa1d1937eU, 0x38d8c2c4U, 0x4fdff252U, 0xd1bb67f1U,
99         0xa6bc5767U, 0x3fb506ddU, 0x48b2364bU, 0xd80d2bdaU, 0xaf0a1b4cU,
100         0x36034af6U, 0x41047a60U, 0xdf60efc3U, 0xa867df55U, 0x316e8eefU,
101         0x4669be79U, 0xcb61b38cU, 0xbc66831aU, 0x256fd2a0U, 0x5268e236U,
102         0xcc0c7795U, 0xbb0b4703U, 0x220216b9U, 0x5505262fU, 0xc5ba3bbeU,
103         0xb2bd0b28U, 0x2bb45a92U, 0x5cb36a04U, 0xc2d7ffa7U, 0xb5d0cf31U,
104         0x2cd99e8bU, 0x5bdeae1dU, 0x9b64c2b0U, 0xec63f226U, 0x756aa39cU,
105         0x026d930aU, 0x9c0906a9U, 0xeb0e363fU, 0x72076785U, 0x05005713U,
106         0x95bf4a82U, 0xe2b87a14U, 0x7bb12baeU, 0x0cb61b38U, 0x92d28e9bU,
107         0xe5d5be0dU, 0x7cdcefb7U, 0x0bdbdf21U, 0x86d3d2d4U, 0xf1d4e242U,
108         0x68ddb3f8U, 0x1fda836eU, 0x81be16cdU, 0xf6b9265bU, 0x6fb077e1U,
109         0x18b74777U, 0x88085ae6U, 0xff0f6a70U, 0x66063bcaU, 0x11010b5cU,
110         0x8f659effU, 0xf862ae69U, 0x616bffd3U, 0x166ccf45U, 0xa00ae278U,
111         0xd70dd2eeU, 0x4e048354U, 0x3903b3c2U, 0xa7672661U, 0xd06016f7U,
112         0x4969474dU, 0x3e6e77dbU, 0xaed16a4aU, 0xd9d65adcU, 0x40df0b66U,
113         0x37d83bf0U, 0xa9bcae53U, 0xdebb9ec5U, 0x47b2cf7fU, 0x30b5ffe9U,
114         0xbdbdf21cU, 0xcabac28aU, 0x53b39330U, 0x24b4a3a6U, 0xbad03605U,
115         0xcdd70693U, 0x54de5729U, 0x23d967bfU, 0xb3667a2eU, 0xc4614ab8U,
116         0x5d681b02U, 0x2a6f2b94U, 0xb40bbe37U, 0xc30c8ea1U, 0x5a05df1bU,
117         0x2d02ef8dU
118 };
119
120 static unsigned long partial_crc32_one(unsigned char c, unsigned long crc)
121 {
122         return crctab32[(crc ^ c) & 0xff] ^ (crc >> 8);
123 }
124
125 static unsigned long partial_crc32(const char *s, unsigned long crc)
126 {
127         while (*s)
128                 crc = partial_crc32_one(*s++, crc);
129         return crc;
130 }
131
132 static unsigned long crc32(const char *s)
133 {
134         return partial_crc32(s, 0xffffffff) ^ 0xffffffff;
135 }
136
137 /*----------------------------------------------------------------------*/
138
139 static enum symbol_type map_to_ns(enum symbol_type t)
140 {
141         switch (t) {
142         case SYM_ENUM_CONST:
143         case SYM_NORMAL:
144         case SYM_TYPEDEF:
145                 return SYM_NORMAL;
146         case SYM_ENUM:
147         case SYM_STRUCT:
148         case SYM_UNION:
149                 return SYM_STRUCT;
150         }
151         return t;
152 }
153
154 struct symbol *find_symbol(const char *name, enum symbol_type ns, int exact)
155 {
156         unsigned long h = crc32(name) % HASH_BUCKETS;
157         struct symbol *sym;
158
159         for (sym = symtab[h]; sym; sym = sym->hash_next)
160                 if (map_to_ns(sym->type) == map_to_ns(ns) &&
161                     strcmp(name, sym->name) == 0 &&
162                     sym->is_declared)
163                         break;
164
165         if (exact && sym && sym->type != ns)
166                 return NULL;
167         return sym;
168 }
169
170 static int is_unknown_symbol(struct symbol *sym)
171 {
172         struct string_list *defn;
173
174         return ((sym->type == SYM_STRUCT ||
175                  sym->type == SYM_UNION ||
176                  sym->type == SYM_ENUM) &&
177                 (defn = sym->defn)  && defn->tag == SYM_NORMAL &&
178                         strcmp(defn->string, "}") == 0 &&
179                 (defn = defn->next) && defn->tag == SYM_NORMAL &&
180                         strcmp(defn->string, "UNKNOWN") == 0 &&
181                 (defn = defn->next) && defn->tag == SYM_NORMAL &&
182                         strcmp(defn->string, "{") == 0);
183 }
184
185 static struct symbol *__add_symbol(const char *name, enum symbol_type type,
186                             struct string_list *defn, int is_extern,
187                             int is_reference)
188 {
189         unsigned long h;
190         struct symbol *sym;
191         enum symbol_status status = STATUS_UNCHANGED;
192         /* The parser adds symbols in the order their declaration completes,
193          * so it is safe to store the value of the previous enum constant in
194          * a static variable.
195          */
196         static int enum_counter;
197         static struct string_list *last_enum_expr;
198
199         if (type == SYM_ENUM_CONST) {
200                 if (defn) {
201                         free_list(last_enum_expr, NULL);
202                         last_enum_expr = copy_list_range(defn, NULL);
203                         enum_counter = 1;
204                 } else {
205                         struct string_list *expr;
206                         char buf[20];
207
208                         snprintf(buf, sizeof(buf), "%d", enum_counter++);
209                         if (last_enum_expr) {
210                                 expr = copy_list_range(last_enum_expr, NULL);
211                                 defn = concat_list(mk_node("("),
212                                                    expr,
213                                                    mk_node(")"),
214                                                    mk_node("+"),
215                                                    mk_node(buf), NULL);
216                         } else {
217                                 defn = mk_node(buf);
218                         }
219                 }
220         } else if (type == SYM_ENUM) {
221                 free_list(last_enum_expr, NULL);
222                 last_enum_expr = NULL;
223                 enum_counter = 0;
224                 if (!name)
225                         /* Anonymous enum definition, nothing more to do */
226                         return NULL;
227         }
228
229         h = crc32(name) % HASH_BUCKETS;
230         for (sym = symtab[h]; sym; sym = sym->hash_next) {
231                 if (map_to_ns(sym->type) == map_to_ns(type) &&
232                     strcmp(name, sym->name) == 0) {
233                         if (is_reference)
234                                 /* fall through */ ;
235                         else if (sym->type == type &&
236                                  equal_list(sym->defn, defn)) {
237                                 if (!sym->is_declared && sym->is_override) {
238                                         print_location();
239                                         print_type_name(type, name);
240                                         fprintf(stderr, " modversion is "
241                                                 "unchanged\n");
242                                 }
243                                 sym->is_declared = 1;
244                                 return sym;
245                         } else if (!sym->is_declared) {
246                                 if (sym->is_override && flag_preserve) {
247                                         print_location();
248                                         fprintf(stderr, "ignoring ");
249                                         print_type_name(type, name);
250                                         fprintf(stderr, " modversion change\n");
251                                         sym->is_declared = 1;
252                                         return sym;
253                                 } else {
254                                         status = is_unknown_symbol(sym) ?
255                                                 STATUS_DEFINED : STATUS_MODIFIED;
256                                 }
257                         } else {
258                                 error_with_pos("redefinition of %s", name);
259                                 return sym;
260                         }
261                         break;
262                 }
263         }
264
265         if (sym) {
266                 struct symbol **psym;
267
268                 for (psym = &symtab[h]; *psym; psym = &(*psym)->hash_next) {
269                         if (*psym == sym) {
270                                 *psym = sym->hash_next;
271                                 break;
272                         }
273                 }
274                 --nsyms;
275         }
276
277         sym = xmalloc(sizeof(*sym));
278         sym->name = name;
279         sym->type = type;
280         sym->defn = defn;
281         sym->expansion_trail = NULL;
282         sym->visited = NULL;
283         sym->is_extern = is_extern;
284
285         sym->hash_next = symtab[h];
286         symtab[h] = sym;
287
288         sym->is_declared = !is_reference;
289         sym->status = status;
290         sym->is_override = 0;
291
292         if (flag_debug) {
293                 if (symbol_types[type].name)
294                         fprintf(debugfile, "Defn for %s %s == <",
295                                 symbol_types[type].name, name);
296                 else
297                         fprintf(debugfile, "Defn for type%d %s == <",
298                                 type, name);
299                 if (is_extern)
300                         fputs("extern ", debugfile);
301                 print_list(debugfile, defn);
302                 fputs(">\n", debugfile);
303         }
304
305         ++nsyms;
306         return sym;
307 }
308
309 struct symbol *add_symbol(const char *name, enum symbol_type type,
310                           struct string_list *defn, int is_extern)
311 {
312         return __add_symbol(name, type, defn, is_extern, 0);
313 }
314
315 static struct symbol *add_reference_symbol(const char *name, enum symbol_type type,
316                                     struct string_list *defn, int is_extern)
317 {
318         return __add_symbol(name, type, defn, is_extern, 1);
319 }
320
321 /*----------------------------------------------------------------------*/
322
323 void free_node(struct string_list *node)
324 {
325         free(node->string);
326         free(node);
327 }
328
329 void free_list(struct string_list *s, struct string_list *e)
330 {
331         while (s != e) {
332                 struct string_list *next = s->next;
333                 free_node(s);
334                 s = next;
335         }
336 }
337
338 static struct string_list *mk_node(const char *string)
339 {
340         struct string_list *newnode;
341
342         newnode = xmalloc(sizeof(*newnode));
343         newnode->string = xstrdup(string);
344         newnode->tag = SYM_NORMAL;
345         newnode->next = NULL;
346
347         return newnode;
348 }
349
350 static struct string_list *concat_list(struct string_list *start, ...)
351 {
352         va_list ap;
353         struct string_list *n, *n2;
354
355         if (!start)
356                 return NULL;
357         for (va_start(ap, start); (n = va_arg(ap, struct string_list *));) {
358                 for (n2 = n; n2->next; n2 = n2->next)
359                         ;
360                 n2->next = start;
361                 start = n;
362         }
363         va_end(ap);
364         return start;
365 }
366
367 struct string_list *copy_node(struct string_list *node)
368 {
369         struct string_list *newnode;
370
371         newnode = xmalloc(sizeof(*newnode));
372         newnode->string = xstrdup(node->string);
373         newnode->tag = node->tag;
374
375         return newnode;
376 }
377
378 struct string_list *copy_list_range(struct string_list *start,
379                                     struct string_list *end)
380 {
381         struct string_list *res, *n;
382
383         if (start == end)
384                 return NULL;
385         n = res = copy_node(start);
386         for (start = start->next; start != end; start = start->next) {
387                 n->next = copy_node(start);
388                 n = n->next;
389         }
390         n->next = NULL;
391         return res;
392 }
393
394 static int equal_list(struct string_list *a, struct string_list *b)
395 {
396         while (a && b) {
397                 if (a->tag != b->tag || strcmp(a->string, b->string))
398                         return 0;
399                 a = a->next;
400                 b = b->next;
401         }
402
403         return !a && !b;
404 }
405
406 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
407
408 static struct string_list *read_node(FILE *f)
409 {
410         char buffer[256];
411         struct string_list node = {
412                 .string = buffer,
413                 .tag = SYM_NORMAL };
414         int c, in_string = 0;
415
416         while ((c = fgetc(f)) != EOF) {
417                 if (!in_string && c == ' ') {
418                         if (node.string == buffer)
419                                 continue;
420                         break;
421                 } else if (c == '"') {
422                         in_string = !in_string;
423                 } else if (c == '\n') {
424                         if (node.string == buffer)
425                                 return NULL;
426                         ungetc(c, f);
427                         break;
428                 }
429                 if (node.string >= buffer + sizeof(buffer) - 1) {
430                         fprintf(stderr, "Token too long\n");
431                         exit(1);
432                 }
433                 *node.string++ = c;
434         }
435         if (node.string == buffer)
436                 return NULL;
437         *node.string = 0;
438         node.string = buffer;
439
440         if (node.string[1] == '#') {
441                 size_t n;
442
443                 for (n = 0; n < ARRAY_SIZE(symbol_types); n++) {
444                         if (node.string[0] == symbol_types[n].n) {
445                                 node.tag = n;
446                                 node.string += 2;
447                                 return copy_node(&node);
448                         }
449                 }
450                 fprintf(stderr, "Unknown type %c\n", node.string[0]);
451                 exit(1);
452         }
453         return copy_node(&node);
454 }
455
456 static void read_reference(FILE *f)
457 {
458         while (!feof(f)) {
459                 struct string_list *defn = NULL;
460                 struct string_list *sym, *def;
461                 int is_extern = 0, is_override = 0;
462                 struct symbol *subsym;
463
464                 sym = read_node(f);
465                 if (sym && sym->tag == SYM_NORMAL &&
466                     !strcmp(sym->string, "override")) {
467                         is_override = 1;
468                         free_node(sym);
469                         sym = read_node(f);
470                 }
471                 if (!sym)
472                         continue;
473                 def = read_node(f);
474                 if (def && def->tag == SYM_NORMAL &&
475                     !strcmp(def->string, "extern")) {
476                         is_extern = 1;
477                         free_node(def);
478                         def = read_node(f);
479                 }
480                 while (def) {
481                         def->next = defn;
482                         defn = def;
483                         def = read_node(f);
484                 }
485                 subsym = add_reference_symbol(xstrdup(sym->string), sym->tag,
486                                               defn, is_extern);
487                 subsym->is_override = is_override;
488                 free_node(sym);
489         }
490 }
491
492 static void print_node(FILE * f, struct string_list *list)
493 {
494         if (symbol_types[list->tag].n) {
495                 putc(symbol_types[list->tag].n, f);
496                 putc('#', f);
497         }
498         fputs(list->string, f);
499 }
500
501 static void print_list(FILE * f, struct string_list *list)
502 {
503         struct string_list **e, **b;
504         struct string_list *tmp, **tmp2;
505         int elem = 1;
506
507         if (list == NULL) {
508                 fputs("(nil)", f);
509                 return;
510         }
511
512         tmp = list;
513         while ((tmp = tmp->next) != NULL)
514                 elem++;
515
516         b = alloca(elem * sizeof(*e));
517         e = b + elem;
518         tmp2 = e - 1;
519
520         (*tmp2--) = list;
521         while ((list = list->next) != NULL)
522                 *(tmp2--) = list;
523
524         while (b != e) {
525                 print_node(f, *b++);
526                 putc(' ', f);
527         }
528 }
529
530 static unsigned long expand_and_crc_sym(struct symbol *sym, unsigned long crc)
531 {
532         struct string_list *list = sym->defn;
533         struct string_list **e, **b;
534         struct string_list *tmp, **tmp2;
535         int elem = 1;
536
537         if (!list)
538                 return crc;
539
540         tmp = list;
541         while ((tmp = tmp->next) != NULL)
542                 elem++;
543
544         b = alloca(elem * sizeof(*e));
545         e = b + elem;
546         tmp2 = e - 1;
547
548         *(tmp2--) = list;
549         while ((list = list->next) != NULL)
550                 *(tmp2--) = list;
551
552         while (b != e) {
553                 struct string_list *cur;
554                 struct symbol *subsym;
555
556                 cur = *(b++);
557                 switch (cur->tag) {
558                 case SYM_NORMAL:
559                         if (flag_dump_defs)
560                                 fprintf(debugfile, "%s ", cur->string);
561                         crc = partial_crc32(cur->string, crc);
562                         crc = partial_crc32_one(' ', crc);
563                         break;
564
565                 case SYM_ENUM_CONST:
566                 case SYM_TYPEDEF:
567                         subsym = find_symbol(cur->string, cur->tag, 0);
568                         /* FIXME: Bad reference files can segfault here. */
569                         if (subsym->expansion_trail) {
570                                 if (flag_dump_defs)
571                                         fprintf(debugfile, "%s ", cur->string);
572                                 crc = partial_crc32(cur->string, crc);
573                                 crc = partial_crc32_one(' ', crc);
574                         } else {
575                                 subsym->expansion_trail = expansion_trail;
576                                 expansion_trail = subsym;
577                                 crc = expand_and_crc_sym(subsym, crc);
578                         }
579                         break;
580
581                 case SYM_STRUCT:
582                 case SYM_UNION:
583                 case SYM_ENUM:
584                         subsym = find_symbol(cur->string, cur->tag, 0);
585                         if (!subsym) {
586                                 struct string_list *n;
587
588                                 error_with_pos("expand undefined %s %s",
589                                                symbol_types[cur->tag].name,
590                                                cur->string);
591                                 n = concat_list(mk_node
592                                                 (symbol_types[cur->tag].name),
593                                                 mk_node(cur->string),
594                                                 mk_node("{"),
595                                                 mk_node("UNKNOWN"),
596                                                 mk_node("}"), NULL);
597                                 subsym =
598                                     add_symbol(cur->string, cur->tag, n, 0);
599                         }
600                         if (subsym->expansion_trail) {
601                                 if (flag_dump_defs) {
602                                         fprintf(debugfile, "%s %s ",
603                                                 symbol_types[cur->tag].name,
604                                                 cur->string);
605                                 }
606
607                                 crc = partial_crc32(symbol_types[cur->tag].name,
608                                                     crc);
609                                 crc = partial_crc32_one(' ', crc);
610                                 crc = partial_crc32(cur->string, crc);
611                                 crc = partial_crc32_one(' ', crc);
612                         } else {
613                                 subsym->expansion_trail = expansion_trail;
614                                 expansion_trail = subsym;
615                                 crc = expand_and_crc_sym(subsym, crc);
616                         }
617                         break;
618                 }
619         }
620
621         {
622                 static struct symbol **end = &visited_symbols;
623
624                 if (!sym->visited) {
625                         *end = sym;
626                         end = &sym->visited;
627                         sym->visited = (struct symbol *)-1L;
628                 }
629         }
630
631         return crc;
632 }
633
634 void export_symbol(const char *name)
635 {
636         struct symbol *sym;
637
638         sym = find_symbol(name, SYM_NORMAL, 0);
639         if (!sym)
640                 error_with_pos("export undefined symbol %s", name);
641         else {
642                 unsigned long crc;
643                 int has_changed = 0;
644
645                 if (flag_dump_defs)
646                         fprintf(debugfile, "Export %s == <", name);
647
648                 expansion_trail = (struct symbol *)-1L;
649
650                 sym->expansion_trail = expansion_trail;
651                 expansion_trail = sym;
652                 crc = expand_and_crc_sym(sym, 0xffffffff) ^ 0xffffffff;
653
654                 sym = expansion_trail;
655                 while (sym != (struct symbol *)-1L) {
656                         struct symbol *n = sym->expansion_trail;
657
658                         if (sym->status != STATUS_UNCHANGED) {
659                                 if (!has_changed) {
660                                         print_location();
661                                         fprintf(stderr, "%s: %s: modversion "
662                                                 "changed because of changes "
663                                                 "in ", flag_preserve ? "error" :
664                                                        "warning", name);
665                                 } else
666                                         fprintf(stderr, ", ");
667                                 print_type_name(sym->type, sym->name);
668                                 if (sym->status == STATUS_DEFINED)
669                                         fprintf(stderr, " (became defined)");
670                                 has_changed = 1;
671                                 if (flag_preserve)
672                                         errors++;
673                         }
674                         sym->expansion_trail = 0;
675                         sym = n;
676                 }
677                 if (has_changed)
678                         fprintf(stderr, "\n");
679
680                 if (flag_dump_defs)
681                         fputs(">\n", debugfile);
682
683                 printf("#SYMVER %s 0x%08lx\n", name, crc);
684         }
685 }
686
687 /*----------------------------------------------------------------------*/
688
689 static void print_location(void)
690 {
691         fprintf(stderr, "%s:%d: ", cur_filename ? : "<stdin>", cur_line);
692 }
693
694 static void print_type_name(enum symbol_type type, const char *name)
695 {
696         if (symbol_types[type].name)
697                 fprintf(stderr, "%s %s", symbol_types[type].name, name);
698         else
699                 fprintf(stderr, "%s", name);
700 }
701
702 void error_with_pos(const char *fmt, ...)
703 {
704         va_list args;
705
706         if (flag_warnings) {
707                 print_location();
708
709                 va_start(args, fmt);
710                 vfprintf(stderr, fmt, args);
711                 va_end(args);
712                 putc('\n', stderr);
713
714                 errors++;
715         }
716 }
717
718 static void genksyms_usage(void)
719 {
720         fputs("Usage:\n" "genksyms [-adDTwqhVR] > /path/to/.tmp_obj.ver\n" "\n"
721 #ifdef __GNU_LIBRARY__
722               "  -s, --symbol-prefix   Select symbol prefix\n"
723               "  -d, --debug           Increment the debug level (repeatable)\n"
724               "  -D, --dump            Dump expanded symbol defs (for debugging only)\n"
725               "  -r, --reference file  Read reference symbols from a file\n"
726               "  -T, --dump-types file Dump expanded types into file\n"
727               "  -p, --preserve        Preserve reference modversions or fail\n"
728               "  -w, --warnings        Enable warnings\n"
729               "  -q, --quiet           Disable warnings (default)\n"
730               "  -h, --help            Print this message\n"
731               "  -V, --version         Print the release version\n"
732 #else                           /* __GNU_LIBRARY__ */
733               "  -s                    Select symbol prefix\n"
734               "  -d                    Increment the debug level (repeatable)\n"
735               "  -D                    Dump expanded symbol defs (for debugging only)\n"
736               "  -r file               Read reference symbols from a file\n"
737               "  -T file               Dump expanded types into file\n"
738               "  -p                    Preserve reference modversions or fail\n"
739               "  -w                    Enable warnings\n"
740               "  -q                    Disable warnings (default)\n"
741               "  -h                    Print this message\n"
742               "  -V                    Print the release version\n"
743 #endif                          /* __GNU_LIBRARY__ */
744               , stderr);
745 }
746
747 int main(int argc, char **argv)
748 {
749         FILE *dumpfile = NULL, *ref_file = NULL;
750         int o;
751
752 #ifdef __GNU_LIBRARY__
753         struct option long_opts[] = {
754                 {"debug", 0, 0, 'd'},
755                 {"warnings", 0, 0, 'w'},
756                 {"quiet", 0, 0, 'q'},
757                 {"dump", 0, 0, 'D'},
758                 {"reference", 1, 0, 'r'},
759                 {"dump-types", 1, 0, 'T'},
760                 {"preserve", 0, 0, 'p'},
761                 {"version", 0, 0, 'V'},
762                 {"help", 0, 0, 'h'},
763                 {0, 0, 0, 0}
764         };
765
766         while ((o = getopt_long(argc, argv, "s:dwqVDr:T:ph",
767                                 &long_opts[0], NULL)) != EOF)
768 #else                           /* __GNU_LIBRARY__ */
769         while ((o = getopt(argc, argv, "s:dwqVDr:T:ph")) != EOF)
770 #endif                          /* __GNU_LIBRARY__ */
771                 switch (o) {
772                 case 'd':
773                         flag_debug++;
774                         break;
775                 case 'w':
776                         flag_warnings = 1;
777                         break;
778                 case 'q':
779                         flag_warnings = 0;
780                         break;
781                 case 'V':
782                         fputs("genksyms version 2.5.60\n", stderr);
783                         break;
784                 case 'D':
785                         flag_dump_defs = 1;
786                         break;
787                 case 'r':
788                         flag_reference = 1;
789                         ref_file = fopen(optarg, "r");
790                         if (!ref_file) {
791                                 perror(optarg);
792                                 return 1;
793                         }
794                         break;
795                 case 'T':
796                         flag_dump_types = 1;
797                         dumpfile = fopen(optarg, "w");
798                         if (!dumpfile) {
799                                 perror(optarg);
800                                 return 1;
801                         }
802                         break;
803                 case 'p':
804                         flag_preserve = 1;
805                         break;
806                 case 'h':
807                         genksyms_usage();
808                         return 0;
809                 default:
810                         genksyms_usage();
811                         return 1;
812                 }
813         {
814                 extern int yydebug;
815                 extern int yy_flex_debug;
816
817                 yydebug = (flag_debug > 1);
818                 yy_flex_debug = (flag_debug > 2);
819
820                 debugfile = stderr;
821                 /* setlinebuf(debugfile); */
822         }
823
824         if (flag_reference) {
825                 read_reference(ref_file);
826                 fclose(ref_file);
827         }
828
829         yyparse();
830
831         if (flag_dump_types && visited_symbols) {
832                 while (visited_symbols != (struct symbol *)-1L) {
833                         struct symbol *sym = visited_symbols;
834
835                         if (sym->is_override)
836                                 fputs("override ", dumpfile);
837                         if (symbol_types[sym->type].n) {
838                                 putc(symbol_types[sym->type].n, dumpfile);
839                                 putc('#', dumpfile);
840                         }
841                         fputs(sym->name, dumpfile);
842                         putc(' ', dumpfile);
843                         if (sym->is_extern)
844                                 fputs("extern ", dumpfile);
845                         print_list(dumpfile, sym->defn);
846                         putc('\n', dumpfile);
847
848                         visited_symbols = sym->visited;
849                         sym->visited = NULL;
850                 }
851         }
852
853         if (flag_debug) {
854                 fprintf(debugfile, "Hash table occupancy %d/%d = %g\n",
855                         nsyms, HASH_BUCKETS,
856                         (double)nsyms / (double)HASH_BUCKETS);
857         }
858
859         if (dumpfile)
860                 fclose(dumpfile);
861
862         return errors != 0;
863 }