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