GNU Linux-libre 4.19.264-gnu1
[releases.git] / scripts / genksyms / genksyms.c
1 /* Generate kernel symbol version hashes.
2    Copyright 1996, 1997 Linux International.
3
4    New implementation contributed by Richard Henderson <rth@tamu.edu>
5    Based on original work by Bjorn Ekwall <bj0rn@blox.se>
6
7    This file was part of the Linux modutils 2.4.22: moved back into the
8    kernel sources by Rusty Russell/Kai Germaschewski.
9
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.
14
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.
19
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.  */
23
24 #include <stdio.h>
25 #include <string.h>
26 #include <stdlib.h>
27 #include <unistd.h>
28 #include <assert.h>
29 #include <stdarg.h>
30 #ifdef __GNU_LIBRARY__
31 #include <getopt.h>
32 #endif                          /* __GNU_LIBRARY__ */
33
34 #include "genksyms.h"
35 /*----------------------------------------------------------------------*/
36
37 #define HASH_BUCKETS  4096
38
39 static struct symbol *symtab[HASH_BUCKETS];
40 static FILE *debugfile;
41
42 int cur_line = 1;
43 char *cur_filename, *source_file;
44 int in_source_file;
45
46 static int flag_debug, flag_dump_defs, flag_reference, flag_dump_types,
47            flag_preserve, flag_warnings, flag_rel_crcs;
48
49 static int errors;
50 static int nsyms;
51
52 static struct symbol *expansion_trail;
53 static struct symbol *visited_symbols;
54
55 static const struct {
56         int n;
57         const char *name;
58 } symbol_types[] = {
59         [SYM_NORMAL]     = { 0, NULL},
60         [SYM_TYPEDEF]    = {'t', "typedef"},
61         [SYM_ENUM]       = {'e', "enum"},
62         [SYM_STRUCT]     = {'s', "struct"},
63         [SYM_UNION]      = {'u', "union"},
64         [SYM_ENUM_CONST] = {'E', "enum constant"},
65 };
66
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);
73
74 /*----------------------------------------------------------------------*/
75
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,
128         0x2d02ef8dU
129 };
130
131 static unsigned long partial_crc32_one(unsigned char c, unsigned long crc)
132 {
133         return crctab32[(crc ^ c) & 0xff] ^ (crc >> 8);
134 }
135
136 static unsigned long partial_crc32(const char *s, unsigned long crc)
137 {
138         while (*s)
139                 crc = partial_crc32_one(*s++, crc);
140         return crc;
141 }
142
143 static unsigned long crc32(const char *s)
144 {
145         return partial_crc32(s, 0xffffffff) ^ 0xffffffff;
146 }
147
148 /*----------------------------------------------------------------------*/
149
150 static enum symbol_type map_to_ns(enum symbol_type t)
151 {
152         switch (t) {
153         case SYM_ENUM_CONST:
154         case SYM_NORMAL:
155         case SYM_TYPEDEF:
156                 return SYM_NORMAL;
157         case SYM_ENUM:
158         case SYM_STRUCT:
159         case SYM_UNION:
160                 return SYM_STRUCT;
161         }
162         return t;
163 }
164
165 struct symbol *find_symbol(const char *name, enum symbol_type ns, int exact)
166 {
167         unsigned long h = crc32(name) % HASH_BUCKETS;
168         struct symbol *sym;
169
170         for (sym = symtab[h]; sym; sym = sym->hash_next)
171                 if (map_to_ns(sym->type) == map_to_ns(ns) &&
172                     strcmp(name, sym->name) == 0 &&
173                     sym->is_declared)
174                         break;
175
176         if (exact && sym && sym->type != ns)
177                 return NULL;
178         return sym;
179 }
180
181 static int is_unknown_symbol(struct symbol *sym)
182 {
183         struct string_list *defn;
184
185         return ((sym->type == SYM_STRUCT ||
186                  sym->type == SYM_UNION ||
187                  sym->type == SYM_ENUM) &&
188                 (defn = sym->defn)  && defn->tag == SYM_NORMAL &&
189                         strcmp(defn->string, "}") == 0 &&
190                 (defn = defn->next) && defn->tag == SYM_NORMAL &&
191                         strcmp(defn->string, "UNKNOWN") == 0 &&
192                 (defn = defn->next) && defn->tag == SYM_NORMAL &&
193                         strcmp(defn->string, "{") == 0);
194 }
195
196 static struct symbol *__add_symbol(const char *name, enum symbol_type type,
197                             struct string_list *defn, int is_extern,
198                             int is_reference)
199 {
200         unsigned long h;
201         struct symbol *sym;
202         enum symbol_status status = STATUS_UNCHANGED;
203         /* The parser adds symbols in the order their declaration completes,
204          * so it is safe to store the value of the previous enum constant in
205          * a static variable.
206          */
207         static int enum_counter;
208         static struct string_list *last_enum_expr;
209
210         if (type == SYM_ENUM_CONST) {
211                 if (defn) {
212                         free_list(last_enum_expr, NULL);
213                         last_enum_expr = copy_list_range(defn, NULL);
214                         enum_counter = 1;
215                 } else {
216                         struct string_list *expr;
217                         char buf[20];
218
219                         snprintf(buf, sizeof(buf), "%d", enum_counter++);
220                         if (last_enum_expr) {
221                                 expr = copy_list_range(last_enum_expr, NULL);
222                                 defn = concat_list(mk_node("("),
223                                                    expr,
224                                                    mk_node(")"),
225                                                    mk_node("+"),
226                                                    mk_node(buf), NULL);
227                         } else {
228                                 defn = mk_node(buf);
229                         }
230                 }
231         } else if (type == SYM_ENUM) {
232                 free_list(last_enum_expr, NULL);
233                 last_enum_expr = NULL;
234                 enum_counter = 0;
235                 if (!name)
236                         /* Anonymous enum definition, nothing more to do */
237                         return NULL;
238         }
239
240         h = crc32(name) % HASH_BUCKETS;
241         for (sym = symtab[h]; sym; sym = sym->hash_next) {
242                 if (map_to_ns(sym->type) == map_to_ns(type) &&
243                     strcmp(name, sym->name) == 0) {
244                         if (is_reference)
245                                 /* fall through */ ;
246                         else if (sym->type == type &&
247                                  equal_list(sym->defn, defn)) {
248                                 if (!sym->is_declared && sym->is_override) {
249                                         print_location();
250                                         print_type_name(type, name);
251                                         fprintf(stderr, " modversion is "
252                                                 "unchanged\n");
253                                 }
254                                 sym->is_declared = 1;
255                                 return sym;
256                         } else if (!sym->is_declared) {
257                                 if (sym->is_override && flag_preserve) {
258                                         print_location();
259                                         fprintf(stderr, "ignoring ");
260                                         print_type_name(type, name);
261                                         fprintf(stderr, " modversion change\n");
262                                         sym->is_declared = 1;
263                                         return sym;
264                                 } else {
265                                         status = is_unknown_symbol(sym) ?
266                                                 STATUS_DEFINED : STATUS_MODIFIED;
267                                 }
268                         } else {
269                                 error_with_pos("redefinition of %s", name);
270                                 return sym;
271                         }
272                         break;
273                 }
274         }
275
276         if (sym) {
277                 struct symbol **psym;
278
279                 for (psym = &symtab[h]; *psym; psym = &(*psym)->hash_next) {
280                         if (*psym == sym) {
281                                 *psym = sym->hash_next;
282                                 break;
283                         }
284                 }
285                 --nsyms;
286         }
287
288         sym = xmalloc(sizeof(*sym));
289         sym->name = name;
290         sym->type = type;
291         sym->defn = defn;
292         sym->expansion_trail = NULL;
293         sym->visited = NULL;
294         sym->is_extern = is_extern;
295
296         sym->hash_next = symtab[h];
297         symtab[h] = sym;
298
299         sym->is_declared = !is_reference;
300         sym->status = status;
301         sym->is_override = 0;
302
303         if (flag_debug) {
304                 if (symbol_types[type].name)
305                         fprintf(debugfile, "Defn for %s %s == <",
306                                 symbol_types[type].name, name);
307                 else
308                         fprintf(debugfile, "Defn for type%d %s == <",
309                                 type, name);
310                 if (is_extern)
311                         fputs("extern ", debugfile);
312                 print_list(debugfile, defn);
313                 fputs(">\n", debugfile);
314         }
315
316         ++nsyms;
317         return sym;
318 }
319
320 struct symbol *add_symbol(const char *name, enum symbol_type type,
321                           struct string_list *defn, int is_extern)
322 {
323         return __add_symbol(name, type, defn, is_extern, 0);
324 }
325
326 static struct symbol *add_reference_symbol(const char *name, enum symbol_type type,
327                                     struct string_list *defn, int is_extern)
328 {
329         return __add_symbol(name, type, defn, is_extern, 1);
330 }
331
332 /*----------------------------------------------------------------------*/
333
334 void free_node(struct string_list *node)
335 {
336         free(node->string);
337         free(node);
338 }
339
340 void free_list(struct string_list *s, struct string_list *e)
341 {
342         while (s != e) {
343                 struct string_list *next = s->next;
344                 free_node(s);
345                 s = next;
346         }
347 }
348
349 static struct string_list *mk_node(const char *string)
350 {
351         struct string_list *newnode;
352
353         newnode = xmalloc(sizeof(*newnode));
354         newnode->string = xstrdup(string);
355         newnode->tag = SYM_NORMAL;
356         newnode->next = NULL;
357
358         return newnode;
359 }
360
361 static struct string_list *concat_list(struct string_list *start, ...)
362 {
363         va_list ap;
364         struct string_list *n, *n2;
365
366         if (!start)
367                 return NULL;
368         for (va_start(ap, start); (n = va_arg(ap, struct string_list *));) {
369                 for (n2 = n; n2->next; n2 = n2->next)
370                         ;
371                 n2->next = start;
372                 start = n;
373         }
374         va_end(ap);
375         return start;
376 }
377
378 struct string_list *copy_node(struct string_list *node)
379 {
380         struct string_list *newnode;
381
382         newnode = xmalloc(sizeof(*newnode));
383         newnode->string = xstrdup(node->string);
384         newnode->tag = node->tag;
385
386         return newnode;
387 }
388
389 struct string_list *copy_list_range(struct string_list *start,
390                                     struct string_list *end)
391 {
392         struct string_list *res, *n;
393
394         if (start == end)
395                 return NULL;
396         n = res = copy_node(start);
397         for (start = start->next; start != end; start = start->next) {
398                 n->next = copy_node(start);
399                 n = n->next;
400         }
401         n->next = NULL;
402         return res;
403 }
404
405 static int equal_list(struct string_list *a, struct string_list *b)
406 {
407         while (a && b) {
408                 if (a->tag != b->tag || strcmp(a->string, b->string))
409                         return 0;
410                 a = a->next;
411                 b = b->next;
412         }
413
414         return !a && !b;
415 }
416
417 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
418
419 static struct string_list *read_node(FILE *f)
420 {
421         char buffer[256];
422         struct string_list node = {
423                 .string = buffer,
424                 .tag = SYM_NORMAL };
425         int c, in_string = 0;
426
427         while ((c = fgetc(f)) != EOF) {
428                 if (!in_string && c == ' ') {
429                         if (node.string == buffer)
430                                 continue;
431                         break;
432                 } else if (c == '"') {
433                         in_string = !in_string;
434                 } else if (c == '\n') {
435                         if (node.string == buffer)
436                                 return NULL;
437                         ungetc(c, f);
438                         break;
439                 }
440                 if (node.string >= buffer + sizeof(buffer) - 1) {
441                         fprintf(stderr, "Token too long\n");
442                         exit(1);
443                 }
444                 *node.string++ = c;
445         }
446         if (node.string == buffer)
447                 return NULL;
448         *node.string = 0;
449         node.string = buffer;
450
451         if (node.string[1] == '#') {
452                 size_t n;
453
454                 for (n = 0; n < ARRAY_SIZE(symbol_types); n++) {
455                         if (node.string[0] == symbol_types[n].n) {
456                                 node.tag = n;
457                                 node.string += 2;
458                                 return copy_node(&node);
459                         }
460                 }
461                 fprintf(stderr, "Unknown type %c\n", node.string[0]);
462                 exit(1);
463         }
464         return copy_node(&node);
465 }
466
467 static void read_reference(FILE *f)
468 {
469         while (!feof(f)) {
470                 struct string_list *defn = NULL;
471                 struct string_list *sym, *def;
472                 int is_extern = 0, is_override = 0;
473                 struct symbol *subsym;
474
475                 sym = read_node(f);
476                 if (sym && sym->tag == SYM_NORMAL &&
477                     !strcmp(sym->string, "override")) {
478                         is_override = 1;
479                         free_node(sym);
480                         sym = read_node(f);
481                 }
482                 if (!sym)
483                         continue;
484                 def = read_node(f);
485                 if (def && def->tag == SYM_NORMAL &&
486                     !strcmp(def->string, "extern")) {
487                         is_extern = 1;
488                         free_node(def);
489                         def = read_node(f);
490                 }
491                 while (def) {
492                         def->next = defn;
493                         defn = def;
494                         def = read_node(f);
495                 }
496                 subsym = add_reference_symbol(xstrdup(sym->string), sym->tag,
497                                               defn, is_extern);
498                 subsym->is_override = is_override;
499                 free_node(sym);
500         }
501 }
502
503 static void print_node(FILE * f, struct string_list *list)
504 {
505         if (symbol_types[list->tag].n) {
506                 putc(symbol_types[list->tag].n, f);
507                 putc('#', f);
508         }
509         fputs(list->string, f);
510 }
511
512 static void print_list(FILE * f, struct string_list *list)
513 {
514         struct string_list **e, **b;
515         struct string_list *tmp, **tmp2;
516         int elem = 1;
517
518         if (list == NULL) {
519                 fputs("(nil)", f);
520                 return;
521         }
522
523         tmp = list;
524         while ((tmp = tmp->next) != NULL)
525                 elem++;
526
527         b = alloca(elem * sizeof(*e));
528         e = b + elem;
529         tmp2 = e - 1;
530
531         (*tmp2--) = list;
532         while ((list = list->next) != NULL)
533                 *(tmp2--) = list;
534
535         while (b != e) {
536                 print_node(f, *b++);
537                 putc(' ', f);
538         }
539 }
540
541 static unsigned long expand_and_crc_sym(struct symbol *sym, unsigned long crc)
542 {
543         struct string_list *list = sym->defn;
544         struct string_list **e, **b;
545         struct string_list *tmp, **tmp2;
546         int elem = 1;
547
548         if (!list)
549                 return crc;
550
551         tmp = list;
552         while ((tmp = tmp->next) != NULL)
553                 elem++;
554
555         b = alloca(elem * sizeof(*e));
556         e = b + elem;
557         tmp2 = e - 1;
558
559         *(tmp2--) = list;
560         while ((list = list->next) != NULL)
561                 *(tmp2--) = list;
562
563         while (b != e) {
564                 struct string_list *cur;
565                 struct symbol *subsym;
566
567                 cur = *(b++);
568                 switch (cur->tag) {
569                 case SYM_NORMAL:
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                         break;
575
576                 case SYM_ENUM_CONST:
577                 case SYM_TYPEDEF:
578                         subsym = find_symbol(cur->string, cur->tag, 0);
579                         /* FIXME: Bad reference files can segfault here. */
580                         if (subsym->expansion_trail) {
581                                 if (flag_dump_defs)
582                                         fprintf(debugfile, "%s ", cur->string);
583                                 crc = partial_crc32(cur->string, crc);
584                                 crc = partial_crc32_one(' ', crc);
585                         } else {
586                                 subsym->expansion_trail = expansion_trail;
587                                 expansion_trail = subsym;
588                                 crc = expand_and_crc_sym(subsym, crc);
589                         }
590                         break;
591
592                 case SYM_STRUCT:
593                 case SYM_UNION:
594                 case SYM_ENUM:
595                         subsym = find_symbol(cur->string, cur->tag, 0);
596                         if (!subsym) {
597                                 struct string_list *n;
598
599                                 error_with_pos("expand undefined %s %s",
600                                                symbol_types[cur->tag].name,
601                                                cur->string);
602                                 n = concat_list(mk_node
603                                                 (symbol_types[cur->tag].name),
604                                                 mk_node(cur->string),
605                                                 mk_node("{"),
606                                                 mk_node("UNKNOWN"),
607                                                 mk_node("}"), NULL);
608                                 subsym =
609                                     add_symbol(cur->string, cur->tag, n, 0);
610                         }
611                         if (subsym->expansion_trail) {
612                                 if (flag_dump_defs) {
613                                         fprintf(debugfile, "%s %s ",
614                                                 symbol_types[cur->tag].name,
615                                                 cur->string);
616                                 }
617
618                                 crc = partial_crc32(symbol_types[cur->tag].name,
619                                                     crc);
620                                 crc = partial_crc32_one(' ', crc);
621                                 crc = partial_crc32(cur->string, crc);
622                                 crc = partial_crc32_one(' ', crc);
623                         } else {
624                                 subsym->expansion_trail = expansion_trail;
625                                 expansion_trail = subsym;
626                                 crc = expand_and_crc_sym(subsym, crc);
627                         }
628                         break;
629                 }
630         }
631
632         {
633                 static struct symbol **end = &visited_symbols;
634
635                 if (!sym->visited) {
636                         *end = sym;
637                         end = &sym->visited;
638                         sym->visited = (struct symbol *)-1L;
639                 }
640         }
641
642         return crc;
643 }
644
645 void export_symbol(const char *name)
646 {
647         struct symbol *sym;
648
649         sym = find_symbol(name, SYM_NORMAL, 0);
650         if (!sym)
651                 error_with_pos("export undefined symbol %s", name);
652         else {
653                 unsigned long crc;
654                 int has_changed = 0;
655
656                 if (flag_dump_defs)
657                         fprintf(debugfile, "Export %s == <", name);
658
659                 expansion_trail = (struct symbol *)-1L;
660
661                 sym->expansion_trail = expansion_trail;
662                 expansion_trail = sym;
663                 crc = expand_and_crc_sym(sym, 0xffffffff) ^ 0xffffffff;
664
665                 sym = expansion_trail;
666                 while (sym != (struct symbol *)-1L) {
667                         struct symbol *n = sym->expansion_trail;
668
669                         if (sym->status != STATUS_UNCHANGED) {
670                                 if (!has_changed) {
671                                         print_location();
672                                         fprintf(stderr, "%s: %s: modversion "
673                                                 "changed because of changes "
674                                                 "in ", flag_preserve ? "error" :
675                                                        "warning", name);
676                                 } else
677                                         fprintf(stderr, ", ");
678                                 print_type_name(sym->type, sym->name);
679                                 if (sym->status == STATUS_DEFINED)
680                                         fprintf(stderr, " (became defined)");
681                                 has_changed = 1;
682                                 if (flag_preserve)
683                                         errors++;
684                         }
685                         sym->expansion_trail = 0;
686                         sym = n;
687                 }
688                 if (has_changed)
689                         fprintf(stderr, "\n");
690
691                 if (flag_dump_defs)
692                         fputs(">\n", debugfile);
693
694                 /* Used as a linker script. */
695                 printf(!flag_rel_crcs ? "__crc_%s = 0x%08lx;\n" :
696                        "SECTIONS { .rodata : ALIGN(4) { "
697                        "__crc_%s = .; LONG(0x%08lx); } }\n",
698                        name, crc);
699         }
700 }
701
702 /*----------------------------------------------------------------------*/
703
704 static void print_location(void)
705 {
706         fprintf(stderr, "%s:%d: ", cur_filename ? : "<stdin>", cur_line);
707 }
708
709 static void print_type_name(enum symbol_type type, const char *name)
710 {
711         if (symbol_types[type].name)
712                 fprintf(stderr, "%s %s", symbol_types[type].name, name);
713         else
714                 fprintf(stderr, "%s", name);
715 }
716
717 void error_with_pos(const char *fmt, ...)
718 {
719         va_list args;
720
721         if (flag_warnings) {
722                 print_location();
723
724                 va_start(args, fmt);
725                 vfprintf(stderr, fmt, args);
726                 va_end(args);
727                 putc('\n', stderr);
728
729                 errors++;
730         }
731 }
732
733 static void genksyms_usage(void)
734 {
735         fputs("Usage:\n" "genksyms [-adDTwqhVR] > /path/to/.tmp_obj.ver\n" "\n"
736 #ifdef __GNU_LIBRARY__
737               "  -s, --symbol-prefix   Select symbol prefix\n"
738               "  -d, --debug           Increment the debug level (repeatable)\n"
739               "  -D, --dump            Dump expanded symbol defs (for debugging only)\n"
740               "  -r, --reference file  Read reference symbols from a file\n"
741               "  -T, --dump-types file Dump expanded types into file\n"
742               "  -p, --preserve        Preserve reference modversions or fail\n"
743               "  -w, --warnings        Enable warnings\n"
744               "  -q, --quiet           Disable warnings (default)\n"
745               "  -h, --help            Print this message\n"
746               "  -V, --version         Print the release version\n"
747               "  -R, --relative-crc    Emit section relative symbol CRCs\n"
748 #else                           /* __GNU_LIBRARY__ */
749               "  -s                    Select symbol prefix\n"
750               "  -d                    Increment the debug level (repeatable)\n"
751               "  -D                    Dump expanded symbol defs (for debugging only)\n"
752               "  -r file               Read reference symbols from a file\n"
753               "  -T file               Dump expanded types into file\n"
754               "  -p                    Preserve reference modversions or fail\n"
755               "  -w                    Enable warnings\n"
756               "  -q                    Disable warnings (default)\n"
757               "  -h                    Print this message\n"
758               "  -V                    Print the release version\n"
759               "  -R                    Emit section relative symbol CRCs\n"
760 #endif                          /* __GNU_LIBRARY__ */
761               , stderr);
762 }
763
764 int main(int argc, char **argv)
765 {
766         FILE *dumpfile = NULL, *ref_file = NULL;
767         int o;
768
769 #ifdef __GNU_LIBRARY__
770         struct option long_opts[] = {
771                 {"debug", 0, 0, 'd'},
772                 {"warnings", 0, 0, 'w'},
773                 {"quiet", 0, 0, 'q'},
774                 {"dump", 0, 0, 'D'},
775                 {"reference", 1, 0, 'r'},
776                 {"dump-types", 1, 0, 'T'},
777                 {"preserve", 0, 0, 'p'},
778                 {"version", 0, 0, 'V'},
779                 {"help", 0, 0, 'h'},
780                 {"relative-crc", 0, 0, 'R'},
781                 {0, 0, 0, 0}
782         };
783
784         while ((o = getopt_long(argc, argv, "s:dwqVDr:T:phR",
785                                 &long_opts[0], NULL)) != EOF)
786 #else                           /* __GNU_LIBRARY__ */
787         while ((o = getopt(argc, argv, "s:dwqVDr:T:phR")) != EOF)
788 #endif                          /* __GNU_LIBRARY__ */
789                 switch (o) {
790                 case 'd':
791                         flag_debug++;
792                         break;
793                 case 'w':
794                         flag_warnings = 1;
795                         break;
796                 case 'q':
797                         flag_warnings = 0;
798                         break;
799                 case 'V':
800                         fputs("genksyms version 2.5.60\n", stderr);
801                         break;
802                 case 'D':
803                         flag_dump_defs = 1;
804                         break;
805                 case 'r':
806                         flag_reference = 1;
807                         ref_file = fopen(optarg, "r");
808                         if (!ref_file) {
809                                 perror(optarg);
810                                 return 1;
811                         }
812                         break;
813                 case 'T':
814                         flag_dump_types = 1;
815                         dumpfile = fopen(optarg, "w");
816                         if (!dumpfile) {
817                                 perror(optarg);
818                                 return 1;
819                         }
820                         break;
821                 case 'p':
822                         flag_preserve = 1;
823                         break;
824                 case 'h':
825                         genksyms_usage();
826                         return 0;
827                 case 'R':
828                         flag_rel_crcs = 1;
829                         break;
830                 default:
831                         genksyms_usage();
832                         return 1;
833                 }
834         {
835                 extern int yydebug;
836                 extern int yy_flex_debug;
837
838                 yydebug = (flag_debug > 1);
839                 yy_flex_debug = (flag_debug > 2);
840
841                 debugfile = stderr;
842                 /* setlinebuf(debugfile); */
843         }
844
845         if (flag_reference) {
846                 read_reference(ref_file);
847                 fclose(ref_file);
848         }
849
850         yyparse();
851
852         if (flag_dump_types && visited_symbols) {
853                 while (visited_symbols != (struct symbol *)-1L) {
854                         struct symbol *sym = visited_symbols;
855
856                         if (sym->is_override)
857                                 fputs("override ", dumpfile);
858                         if (symbol_types[sym->type].n) {
859                                 putc(symbol_types[sym->type].n, dumpfile);
860                                 putc('#', dumpfile);
861                         }
862                         fputs(sym->name, dumpfile);
863                         putc(' ', dumpfile);
864                         if (sym->is_extern)
865                                 fputs("extern ", dumpfile);
866                         print_list(dumpfile, sym->defn);
867                         putc('\n', dumpfile);
868
869                         visited_symbols = sym->visited;
870                         sym->visited = NULL;
871                 }
872         }
873
874         if (flag_debug) {
875                 fprintf(debugfile, "Hash table occupancy %d/%d = %g\n",
876                         nsyms, HASH_BUCKETS,
877                         (double)nsyms / (double)HASH_BUCKETS);
878         }
879
880         if (dumpfile)
881                 fclose(dumpfile);
882
883         return errors != 0;
884 }