treewide: Replace GPLv2 boilerplate/reference with SPDX - rule 156
[sfrench/cifs-2.6.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, *source_file;
33 int in_source_file;
34
35 static int flag_debug, flag_dump_defs, flag_reference, flag_dump_types,
36            flag_preserve, flag_warnings, flag_rel_crcs;
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                 /* Used as a linker script. */
684                 printf(!flag_rel_crcs ? "__crc_%s = 0x%08lx;\n" :
685                        "SECTIONS { .rodata : ALIGN(4) { "
686                        "__crc_%s = .; LONG(0x%08lx); } }\n",
687                        name, crc);
688         }
689 }
690
691 /*----------------------------------------------------------------------*/
692
693 static void print_location(void)
694 {
695         fprintf(stderr, "%s:%d: ", cur_filename ? : "<stdin>", cur_line);
696 }
697
698 static void print_type_name(enum symbol_type type, const char *name)
699 {
700         if (symbol_types[type].name)
701                 fprintf(stderr, "%s %s", symbol_types[type].name, name);
702         else
703                 fprintf(stderr, "%s", name);
704 }
705
706 void error_with_pos(const char *fmt, ...)
707 {
708         va_list args;
709
710         if (flag_warnings) {
711                 print_location();
712
713                 va_start(args, fmt);
714                 vfprintf(stderr, fmt, args);
715                 va_end(args);
716                 putc('\n', stderr);
717
718                 errors++;
719         }
720 }
721
722 static void genksyms_usage(void)
723 {
724         fputs("Usage:\n" "genksyms [-adDTwqhVR] > /path/to/.tmp_obj.ver\n" "\n"
725 #ifdef __GNU_LIBRARY__
726               "  -s, --symbol-prefix   Select symbol prefix\n"
727               "  -d, --debug           Increment the debug level (repeatable)\n"
728               "  -D, --dump            Dump expanded symbol defs (for debugging only)\n"
729               "  -r, --reference file  Read reference symbols from a file\n"
730               "  -T, --dump-types file Dump expanded types into file\n"
731               "  -p, --preserve        Preserve reference modversions or fail\n"
732               "  -w, --warnings        Enable warnings\n"
733               "  -q, --quiet           Disable warnings (default)\n"
734               "  -h, --help            Print this message\n"
735               "  -V, --version         Print the release version\n"
736               "  -R, --relative-crc    Emit section relative symbol CRCs\n"
737 #else                           /* __GNU_LIBRARY__ */
738               "  -s                    Select symbol prefix\n"
739               "  -d                    Increment the debug level (repeatable)\n"
740               "  -D                    Dump expanded symbol defs (for debugging only)\n"
741               "  -r file               Read reference symbols from a file\n"
742               "  -T file               Dump expanded types into file\n"
743               "  -p                    Preserve reference modversions or fail\n"
744               "  -w                    Enable warnings\n"
745               "  -q                    Disable warnings (default)\n"
746               "  -h                    Print this message\n"
747               "  -V                    Print the release version\n"
748               "  -R                    Emit section relative symbol CRCs\n"
749 #endif                          /* __GNU_LIBRARY__ */
750               , stderr);
751 }
752
753 int main(int argc, char **argv)
754 {
755         FILE *dumpfile = NULL, *ref_file = NULL;
756         int o;
757
758 #ifdef __GNU_LIBRARY__
759         struct option long_opts[] = {
760                 {"debug", 0, 0, 'd'},
761                 {"warnings", 0, 0, 'w'},
762                 {"quiet", 0, 0, 'q'},
763                 {"dump", 0, 0, 'D'},
764                 {"reference", 1, 0, 'r'},
765                 {"dump-types", 1, 0, 'T'},
766                 {"preserve", 0, 0, 'p'},
767                 {"version", 0, 0, 'V'},
768                 {"help", 0, 0, 'h'},
769                 {"relative-crc", 0, 0, 'R'},
770                 {0, 0, 0, 0}
771         };
772
773         while ((o = getopt_long(argc, argv, "s:dwqVDr:T:phR",
774                                 &long_opts[0], NULL)) != EOF)
775 #else                           /* __GNU_LIBRARY__ */
776         while ((o = getopt(argc, argv, "s:dwqVDr:T:phR")) != EOF)
777 #endif                          /* __GNU_LIBRARY__ */
778                 switch (o) {
779                 case 'd':
780                         flag_debug++;
781                         break;
782                 case 'w':
783                         flag_warnings = 1;
784                         break;
785                 case 'q':
786                         flag_warnings = 0;
787                         break;
788                 case 'V':
789                         fputs("genksyms version 2.5.60\n", stderr);
790                         break;
791                 case 'D':
792                         flag_dump_defs = 1;
793                         break;
794                 case 'r':
795                         flag_reference = 1;
796                         ref_file = fopen(optarg, "r");
797                         if (!ref_file) {
798                                 perror(optarg);
799                                 return 1;
800                         }
801                         break;
802                 case 'T':
803                         flag_dump_types = 1;
804                         dumpfile = fopen(optarg, "w");
805                         if (!dumpfile) {
806                                 perror(optarg);
807                                 return 1;
808                         }
809                         break;
810                 case 'p':
811                         flag_preserve = 1;
812                         break;
813                 case 'h':
814                         genksyms_usage();
815                         return 0;
816                 case 'R':
817                         flag_rel_crcs = 1;
818                         break;
819                 default:
820                         genksyms_usage();
821                         return 1;
822                 }
823         {
824                 extern int yydebug;
825                 extern int yy_flex_debug;
826
827                 yydebug = (flag_debug > 1);
828                 yy_flex_debug = (flag_debug > 2);
829
830                 debugfile = stderr;
831                 /* setlinebuf(debugfile); */
832         }
833
834         if (flag_reference) {
835                 read_reference(ref_file);
836                 fclose(ref_file);
837         }
838
839         yyparse();
840
841         if (flag_dump_types && visited_symbols) {
842                 while (visited_symbols != (struct symbol *)-1L) {
843                         struct symbol *sym = visited_symbols;
844
845                         if (sym->is_override)
846                                 fputs("override ", dumpfile);
847                         if (symbol_types[sym->type].n) {
848                                 putc(symbol_types[sym->type].n, dumpfile);
849                                 putc('#', dumpfile);
850                         }
851                         fputs(sym->name, dumpfile);
852                         putc(' ', dumpfile);
853                         if (sym->is_extern)
854                                 fputs("extern ", dumpfile);
855                         print_list(dumpfile, sym->defn);
856                         putc('\n', dumpfile);
857
858                         visited_symbols = sym->visited;
859                         sym->visited = NULL;
860                 }
861         }
862
863         if (flag_debug) {
864                 fprintf(debugfile, "Hash table occupancy %d/%d = %g\n",
865                         nsyms, HASH_BUCKETS,
866                         (double)nsyms / (double)HASH_BUCKETS);
867         }
868
869         if (dumpfile)
870                 fclose(dumpfile);
871
872         return errors != 0;
873 }