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