kbuild: Lindent genksyms.c
[linux-2.6.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 FILE *debugfile;
41
42 int cur_line = 1;
43 char *cur_filename, *output_directory;
44
45 int flag_debug, flag_dump_defs, flag_warnings;
46 const char *arch = "";
47 const char *mod_prefix = "";
48
49 static int errors;
50 static int nsyms;
51
52 static struct symbol *expansion_trail;
53
54 static const char *const symbol_type_name[] = {
55         "normal", "typedef", "enum", "struct", "union"
56 };
57
58 /*----------------------------------------------------------------------*/
59
60 static const unsigned int crctab32[] = {
61         0x00000000U, 0x77073096U, 0xee0e612cU, 0x990951baU, 0x076dc419U,
62         0x706af48fU, 0xe963a535U, 0x9e6495a3U, 0x0edb8832U, 0x79dcb8a4U,
63         0xe0d5e91eU, 0x97d2d988U, 0x09b64c2bU, 0x7eb17cbdU, 0xe7b82d07U,
64         0x90bf1d91U, 0x1db71064U, 0x6ab020f2U, 0xf3b97148U, 0x84be41deU,
65         0x1adad47dU, 0x6ddde4ebU, 0xf4d4b551U, 0x83d385c7U, 0x136c9856U,
66         0x646ba8c0U, 0xfd62f97aU, 0x8a65c9ecU, 0x14015c4fU, 0x63066cd9U,
67         0xfa0f3d63U, 0x8d080df5U, 0x3b6e20c8U, 0x4c69105eU, 0xd56041e4U,
68         0xa2677172U, 0x3c03e4d1U, 0x4b04d447U, 0xd20d85fdU, 0xa50ab56bU,
69         0x35b5a8faU, 0x42b2986cU, 0xdbbbc9d6U, 0xacbcf940U, 0x32d86ce3U,
70         0x45df5c75U, 0xdcd60dcfU, 0xabd13d59U, 0x26d930acU, 0x51de003aU,
71         0xc8d75180U, 0xbfd06116U, 0x21b4f4b5U, 0x56b3c423U, 0xcfba9599U,
72         0xb8bda50fU, 0x2802b89eU, 0x5f058808U, 0xc60cd9b2U, 0xb10be924U,
73         0x2f6f7c87U, 0x58684c11U, 0xc1611dabU, 0xb6662d3dU, 0x76dc4190U,
74         0x01db7106U, 0x98d220bcU, 0xefd5102aU, 0x71b18589U, 0x06b6b51fU,
75         0x9fbfe4a5U, 0xe8b8d433U, 0x7807c9a2U, 0x0f00f934U, 0x9609a88eU,
76         0xe10e9818U, 0x7f6a0dbbU, 0x086d3d2dU, 0x91646c97U, 0xe6635c01U,
77         0x6b6b51f4U, 0x1c6c6162U, 0x856530d8U, 0xf262004eU, 0x6c0695edU,
78         0x1b01a57bU, 0x8208f4c1U, 0xf50fc457U, 0x65b0d9c6U, 0x12b7e950U,
79         0x8bbeb8eaU, 0xfcb9887cU, 0x62dd1ddfU, 0x15da2d49U, 0x8cd37cf3U,
80         0xfbd44c65U, 0x4db26158U, 0x3ab551ceU, 0xa3bc0074U, 0xd4bb30e2U,
81         0x4adfa541U, 0x3dd895d7U, 0xa4d1c46dU, 0xd3d6f4fbU, 0x4369e96aU,
82         0x346ed9fcU, 0xad678846U, 0xda60b8d0U, 0x44042d73U, 0x33031de5U,
83         0xaa0a4c5fU, 0xdd0d7cc9U, 0x5005713cU, 0x270241aaU, 0xbe0b1010U,
84         0xc90c2086U, 0x5768b525U, 0x206f85b3U, 0xb966d409U, 0xce61e49fU,
85         0x5edef90eU, 0x29d9c998U, 0xb0d09822U, 0xc7d7a8b4U, 0x59b33d17U,
86         0x2eb40d81U, 0xb7bd5c3bU, 0xc0ba6cadU, 0xedb88320U, 0x9abfb3b6U,
87         0x03b6e20cU, 0x74b1d29aU, 0xead54739U, 0x9dd277afU, 0x04db2615U,
88         0x73dc1683U, 0xe3630b12U, 0x94643b84U, 0x0d6d6a3eU, 0x7a6a5aa8U,
89         0xe40ecf0bU, 0x9309ff9dU, 0x0a00ae27U, 0x7d079eb1U, 0xf00f9344U,
90         0x8708a3d2U, 0x1e01f268U, 0x6906c2feU, 0xf762575dU, 0x806567cbU,
91         0x196c3671U, 0x6e6b06e7U, 0xfed41b76U, 0x89d32be0U, 0x10da7a5aU,
92         0x67dd4accU, 0xf9b9df6fU, 0x8ebeeff9U, 0x17b7be43U, 0x60b08ed5U,
93         0xd6d6a3e8U, 0xa1d1937eU, 0x38d8c2c4U, 0x4fdff252U, 0xd1bb67f1U,
94         0xa6bc5767U, 0x3fb506ddU, 0x48b2364bU, 0xd80d2bdaU, 0xaf0a1b4cU,
95         0x36034af6U, 0x41047a60U, 0xdf60efc3U, 0xa867df55U, 0x316e8eefU,
96         0x4669be79U, 0xcb61b38cU, 0xbc66831aU, 0x256fd2a0U, 0x5268e236U,
97         0xcc0c7795U, 0xbb0b4703U, 0x220216b9U, 0x5505262fU, 0xc5ba3bbeU,
98         0xb2bd0b28U, 0x2bb45a92U, 0x5cb36a04U, 0xc2d7ffa7U, 0xb5d0cf31U,
99         0x2cd99e8bU, 0x5bdeae1dU, 0x9b64c2b0U, 0xec63f226U, 0x756aa39cU,
100         0x026d930aU, 0x9c0906a9U, 0xeb0e363fU, 0x72076785U, 0x05005713U,
101         0x95bf4a82U, 0xe2b87a14U, 0x7bb12baeU, 0x0cb61b38U, 0x92d28e9bU,
102         0xe5d5be0dU, 0x7cdcefb7U, 0x0bdbdf21U, 0x86d3d2d4U, 0xf1d4e242U,
103         0x68ddb3f8U, 0x1fda836eU, 0x81be16cdU, 0xf6b9265bU, 0x6fb077e1U,
104         0x18b74777U, 0x88085ae6U, 0xff0f6a70U, 0x66063bcaU, 0x11010b5cU,
105         0x8f659effU, 0xf862ae69U, 0x616bffd3U, 0x166ccf45U, 0xa00ae278U,
106         0xd70dd2eeU, 0x4e048354U, 0x3903b3c2U, 0xa7672661U, 0xd06016f7U,
107         0x4969474dU, 0x3e6e77dbU, 0xaed16a4aU, 0xd9d65adcU, 0x40df0b66U,
108         0x37d83bf0U, 0xa9bcae53U, 0xdebb9ec5U, 0x47b2cf7fU, 0x30b5ffe9U,
109         0xbdbdf21cU, 0xcabac28aU, 0x53b39330U, 0x24b4a3a6U, 0xbad03605U,
110         0xcdd70693U, 0x54de5729U, 0x23d967bfU, 0xb3667a2eU, 0xc4614ab8U,
111         0x5d681b02U, 0x2a6f2b94U, 0xb40bbe37U, 0xc30c8ea1U, 0x5a05df1bU,
112         0x2d02ef8dU
113 };
114
115 static inline unsigned long
116 partial_crc32_one(unsigned char c, unsigned long crc)
117 {
118         return crctab32[(crc ^ c) & 0xff] ^ (crc >> 8);
119 }
120
121 static inline unsigned long partial_crc32(const char *s, unsigned long crc)
122 {
123         while (*s)
124                 crc = partial_crc32_one(*s++, crc);
125         return crc;
126 }
127
128 static inline unsigned long crc32(const char *s)
129 {
130         return partial_crc32(s, 0xffffffff) ^ 0xffffffff;
131 }
132
133 /*----------------------------------------------------------------------*/
134
135 static inline enum symbol_type map_to_ns(enum symbol_type t)
136 {
137         if (t == SYM_TYPEDEF)
138                 t = SYM_NORMAL;
139         else if (t == SYM_UNION)
140                 t = SYM_STRUCT;
141         return t;
142 }
143
144 struct symbol *find_symbol(const char *name, enum symbol_type ns)
145 {
146         unsigned long h = crc32(name) % HASH_BUCKETS;
147         struct symbol *sym;
148
149         for (sym = symtab[h]; sym; sym = sym->hash_next)
150                 if (map_to_ns(sym->type) == map_to_ns(ns)
151                     && strcmp(name, sym->name) == 0)
152                         break;
153
154         return sym;
155 }
156
157 struct symbol *add_symbol(const char *name, enum symbol_type type,
158                           struct string_list *defn, int is_extern)
159 {
160         unsigned long h = crc32(name) % HASH_BUCKETS;
161         struct symbol *sym;
162
163         for (sym = symtab[h]; sym; sym = sym->hash_next)
164                 if (map_to_ns(sym->type) == map_to_ns(type)
165                     && strcmp(name, sym->name) == 0) {
166                         if (!equal_list(sym->defn, defn))
167                                 error_with_pos("redefinition of %s", name);
168                         return sym;
169                 }
170
171         sym = xmalloc(sizeof(*sym));
172         sym->name = name;
173         sym->type = type;
174         sym->defn = defn;
175         sym->expansion_trail = NULL;
176         sym->is_extern = is_extern;
177
178         sym->hash_next = symtab[h];
179         symtab[h] = sym;
180
181         if (flag_debug) {
182                 fprintf(debugfile, "Defn for %s %s == <",
183                         symbol_type_name[type], name);
184                 if (is_extern)
185                         fputs("extern ", debugfile);
186                 print_list(debugfile, defn);
187                 fputs(">\n", debugfile);
188         }
189
190         ++nsyms;
191         return sym;
192 }
193
194 /*----------------------------------------------------------------------*/
195
196 inline void free_node(struct string_list *node)
197 {
198         free(node->string);
199         free(node);
200 }
201
202 void free_list(struct string_list *s, struct string_list *e)
203 {
204         while (s != e) {
205                 struct string_list *next = s->next;
206                 free_node(s);
207                 s = next;
208         }
209 }
210
211 inline struct string_list *copy_node(struct string_list *node)
212 {
213         struct string_list *newnode;
214
215         newnode = xmalloc(sizeof(*newnode));
216         newnode->string = xstrdup(node->string);
217         newnode->tag = node->tag;
218
219         return newnode;
220 }
221
222 struct string_list *copy_list(struct string_list *s, struct string_list *e)
223 {
224         struct string_list *h, *p;
225
226         if (s == e)
227                 return NULL;
228
229         p = h = copy_node(s);
230         while ((s = s->next) != e)
231                 p = p->next = copy_node(s);
232         p->next = NULL;
233
234         return h;
235 }
236
237 int equal_list(struct string_list *a, struct string_list *b)
238 {
239         while (a && b) {
240                 if (a->tag != b->tag || strcmp(a->string, b->string))
241                         return 0;
242                 a = a->next;
243                 b = b->next;
244         }
245
246         return !a && !b;
247 }
248
249 static inline void print_node(FILE * f, struct string_list *list)
250 {
251         switch (list->tag) {
252         case SYM_STRUCT:
253                 putc('s', f);
254                 goto printit;
255         case SYM_UNION:
256                 putc('u', f);
257                 goto printit;
258         case SYM_ENUM:
259                 putc('e', f);
260                 goto printit;
261         case SYM_TYPEDEF:
262                 putc('t', f);
263                 goto printit;
264
265               printit:
266                 putc('#', f);
267         case SYM_NORMAL:
268                 fputs(list->string, f);
269                 break;
270         }
271 }
272
273 void print_list(FILE * f, struct string_list *list)
274 {
275         struct string_list **e, **b;
276         struct string_list *tmp, **tmp2;
277         int elem = 1;
278
279         if (list == NULL) {
280                 fputs("(nil)", f);
281                 return;
282         }
283
284         tmp = list;
285         while ((tmp = tmp->next) != NULL)
286                 elem++;
287
288         b = alloca(elem * sizeof(*e));
289         e = b + elem;
290         tmp2 = e - 1;
291
292         (*tmp2--) = list;
293         while ((list = list->next) != NULL)
294                 *(tmp2--) = list;
295
296         while (b != e) {
297                 print_node(f, *b++);
298                 putc(' ', f);
299         }
300 }
301
302 static unsigned long
303 expand_and_crc_list(struct string_list *list, unsigned long crc)
304 {
305         struct string_list **e, **b;
306         struct string_list *tmp, **tmp2;
307         int elem = 1;
308
309         if (!list)
310                 return crc;
311
312         tmp = list;
313         while ((tmp = tmp->next) != NULL)
314                 elem++;
315
316         b = alloca(elem * sizeof(*e));
317         e = b + elem;
318         tmp2 = e - 1;
319
320         *(tmp2--) = list;
321         while ((list = list->next) != NULL)
322                 *(tmp2--) = list;
323
324         while (b != e) {
325                 struct string_list *cur;
326                 struct symbol *subsym;
327
328                 cur = *(b++);
329                 switch (cur->tag) {
330                 case SYM_NORMAL:
331                         if (flag_dump_defs)
332                                 fprintf(debugfile, "%s ", cur->string);
333                         crc = partial_crc32(cur->string, crc);
334                         crc = partial_crc32_one(' ', crc);
335                         break;
336
337                 case SYM_TYPEDEF:
338                         subsym = find_symbol(cur->string, cur->tag);
339                         if (subsym->expansion_trail) {
340                                 if (flag_dump_defs)
341                                         fprintf(debugfile, "%s ", cur->string);
342                                 crc = partial_crc32(cur->string, crc);
343                                 crc = partial_crc32_one(' ', crc);
344                         } else {
345                                 subsym->expansion_trail = expansion_trail;
346                                 expansion_trail = subsym;
347                                 crc = expand_and_crc_list(subsym->defn, crc);
348                         }
349                         break;
350
351                 case SYM_STRUCT:
352                 case SYM_UNION:
353                 case SYM_ENUM:
354                         subsym = find_symbol(cur->string, cur->tag);
355                         if (!subsym) {
356                                 struct string_list *n, *t = NULL;
357
358                                 error_with_pos("expand undefined %s %s",
359                                                symbol_type_name[cur->tag],
360                                                cur->string);
361
362                                 n = xmalloc(sizeof(*n));
363                                 n->string = xstrdup(symbol_type_name[cur->tag]);
364                                 n->tag = SYM_NORMAL;
365                                 n->next = t;
366                                 t = n;
367
368                                 n = xmalloc(sizeof(*n));
369                                 n->string = xstrdup(cur->string);
370                                 n->tag = SYM_NORMAL;
371                                 n->next = t;
372                                 t = n;
373
374                                 n = xmalloc(sizeof(*n));
375                                 n->string = xstrdup("{ UNKNOWN }");
376                                 n->tag = SYM_NORMAL;
377                                 n->next = t;
378
379                                 subsym =
380                                     add_symbol(cur->string, cur->tag, n, 0);
381                         }
382                         if (subsym->expansion_trail) {
383                                 if (flag_dump_defs) {
384                                         fprintf(debugfile, "%s %s ",
385                                                 symbol_type_name[cur->tag],
386                                                 cur->string);
387                                 }
388
389                                 crc =
390                                     partial_crc32(symbol_type_name[cur->tag],
391                                                   crc);
392                                 crc = partial_crc32_one(' ', crc);
393                                 crc = partial_crc32(cur->string, crc);
394                                 crc = partial_crc32_one(' ', crc);
395                         } else {
396                                 subsym->expansion_trail = expansion_trail;
397                                 expansion_trail = subsym;
398                                 crc = expand_and_crc_list(subsym->defn, crc);
399                         }
400                         break;
401                 }
402         }
403
404         return crc;
405 }
406
407 void export_symbol(const char *name)
408 {
409         struct symbol *sym;
410
411         sym = find_symbol(name, SYM_NORMAL);
412         if (!sym)
413                 error_with_pos("export undefined symbol %s", name);
414         else {
415                 unsigned long crc;
416
417                 if (flag_dump_defs)
418                         fprintf(debugfile, "Export %s == <", name);
419
420                 expansion_trail = (struct symbol *)-1L;
421
422                 crc = expand_and_crc_list(sym->defn, 0xffffffff) ^ 0xffffffff;
423
424                 sym = expansion_trail;
425                 while (sym != (struct symbol *)-1L) {
426                         struct symbol *n = sym->expansion_trail;
427                         sym->expansion_trail = 0;
428                         sym = n;
429                 }
430
431                 if (flag_dump_defs)
432                         fputs(">\n", debugfile);
433
434                 /* Used as a linker script. */
435                 printf("%s__crc_%s = 0x%08lx ;\n", mod_prefix, name, crc);
436         }
437 }
438
439 /*----------------------------------------------------------------------*/
440
441 void error(const char *fmt, ...)
442 {
443         va_list args;
444
445         if (flag_warnings) {
446                 va_start(args, fmt);
447                 vfprintf(stderr, fmt, args);
448                 va_end(args);
449                 putc('\n', stderr);
450
451                 errors++;
452         }
453 }
454
455 void error_with_pos(const char *fmt, ...)
456 {
457         va_list args;
458
459         if (flag_warnings) {
460                 fprintf(stderr, "%s:%d: ", cur_filename ? : "<stdin>",
461                         cur_line);
462
463                 va_start(args, fmt);
464                 vfprintf(stderr, fmt, args);
465                 va_end(args);
466                 putc('\n', stderr);
467
468                 errors++;
469         }
470 }
471
472 void genksyms_usage(void)
473 {
474         fputs("Usage:\n" "genksyms [-dDwqhV] > /path/to/.tmp_obj.ver\n" "\n"
475 #ifdef __GNU_LIBRARY__
476               "  -d, --debug           Increment the debug level (repeatable)\n"
477               "  -D, --dump            Dump expanded symbol defs (for debugging only)\n"
478               "  -w, --warnings        Enable warnings\n"
479               "  -q, --quiet           Disable warnings (default)\n"
480               "  -h, --help            Print this message\n"
481               "  -V, --version         Print the release version\n"
482 #else                           /* __GNU_LIBRARY__ */
483               "  -d                    Increment the debug level (repeatable)\n"
484               "  -D                    Dump expanded symbol defs (for debugging only)\n"
485               "  -w                    Enable warnings\n"
486               "  -q                    Disable warnings (default)\n"
487               "  -h                    Print this message\n"
488               "  -V                    Print the release version\n"
489 #endif                          /* __GNU_LIBRARY__ */
490               , stderr);
491 }
492
493 int main(int argc, char **argv)
494 {
495         int o;
496
497 #ifdef __GNU_LIBRARY__
498         struct option long_opts[] = {
499                 {"arch", 1, 0, 'a'},
500                 {"debug", 0, 0, 'd'},
501                 {"warnings", 0, 0, 'w'},
502                 {"quiet", 0, 0, 'q'},
503                 {"dump", 0, 0, 'D'},
504                 {"version", 0, 0, 'V'},
505                 {"help", 0, 0, 'h'},
506                 {0, 0, 0, 0}
507         };
508
509         while ((o = getopt_long(argc, argv, "a:dwqVDk:p:",
510                                 &long_opts[0], NULL)) != EOF)
511 #else                           /* __GNU_LIBRARY__ */
512         while ((o = getopt(argc, argv, "a:dwqVDk:p:")) != EOF)
513 #endif                          /* __GNU_LIBRARY__ */
514                 switch (o) {
515                 case 'a':
516                         arch = optarg;
517                         break;
518                 case 'd':
519                         flag_debug++;
520                         break;
521                 case 'w':
522                         flag_warnings = 1;
523                         break;
524                 case 'q':
525                         flag_warnings = 0;
526                         break;
527                 case 'V':
528                         fputs("genksyms version 2.5.60\n", stderr);
529                         break;
530                 case 'D':
531                         flag_dump_defs = 1;
532                         break;
533                 case 'h':
534                         genksyms_usage();
535                         return 0;
536                 default:
537                         genksyms_usage();
538                         return 1;
539                 }
540         if ((strcmp(arch, "v850") == 0) || (strcmp(arch, "h8300") == 0))
541                 mod_prefix = "_";
542         {
543                 extern int yydebug;
544                 extern int yy_flex_debug;
545
546                 yydebug = (flag_debug > 1);
547                 yy_flex_debug = (flag_debug > 2);
548
549                 debugfile = stderr;
550                 /* setlinebuf(debugfile); */
551         }
552
553         yyparse();
554
555         if (flag_debug) {
556                 fprintf(debugfile, "Hash table occupancy %d/%d = %g\n",
557                         nsyms, HASH_BUCKETS,
558                         (double)nsyms / (double)HASH_BUCKETS);
559         }
560
561         return errors != 0;
562 }