• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/scripts/genksyms/
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
39static struct symbol *symtab[HASH_BUCKETS];
40static FILE *debugfile;
41
42int cur_line = 1;
43char *cur_filename;
44
45static int flag_debug, flag_dump_defs, flag_reference, flag_dump_types,
46	   flag_preserve, flag_warnings;
47static const char *arch = "";
48static const char *mod_prefix = "";
49
50static int errors;
51static int nsyms;
52
53static struct symbol *expansion_trail;
54static struct symbol *visited_symbols;
55
56static const char *const symbol_type_name[] = {
57	"normal", "typedef", "enum", "struct", "union"
58};
59
60static int equal_list(struct string_list *a, struct string_list *b);
61static void print_list(FILE * f, struct string_list *list);
62static void print_location(void);
63static void print_type_name(enum symbol_type type, const char *name);
64
65/*----------------------------------------------------------------------*/
66
67static 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
122static unsigned long partial_crc32_one(unsigned char c, unsigned long crc)
123{
124	return crctab32[(crc ^ c) & 0xff] ^ (crc >> 8);
125}
126
127static 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
134static unsigned long crc32(const char *s)
135{
136	return partial_crc32(s, 0xffffffff) ^ 0xffffffff;
137}
138
139/*----------------------------------------------------------------------*/
140
141static 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
150struct 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
164static 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
179static 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
262struct 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
268static 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
276void free_node(struct string_list *node)
277{
278	free(node->string);
279	free(node);
280}
281
282void 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
291struct 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
302static 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
316static 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
362static 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
398static 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
407static 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
436static 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			if (subsym->expansion_trail) {
474				if (flag_dump_defs)
475					fprintf(debugfile, "%s ", cur->string);
476				crc = partial_crc32(cur->string, crc);
477				crc = partial_crc32_one(' ', crc);
478			} else {
479				subsym->expansion_trail = expansion_trail;
480				expansion_trail = subsym;
481				crc = expand_and_crc_sym(subsym, crc);
482			}
483			break;
484
485		case SYM_STRUCT:
486		case SYM_UNION:
487		case SYM_ENUM:
488			subsym = find_symbol(cur->string, cur->tag);
489			if (!subsym) {
490				struct string_list *n, *t = NULL;
491
492				error_with_pos("expand undefined %s %s",
493					       symbol_type_name[cur->tag],
494					       cur->string);
495
496				n = xmalloc(sizeof(*n));
497				n->string = xstrdup(symbol_type_name[cur->tag]);
498				n->tag = SYM_NORMAL;
499				n->next = t;
500				t = n;
501
502				n = xmalloc(sizeof(*n));
503				n->string = xstrdup(cur->string);
504				n->tag = SYM_NORMAL;
505				n->next = t;
506				t = n;
507
508				n = xmalloc(sizeof(*n));
509				n->string = xstrdup("{");
510				n->tag = SYM_NORMAL;
511				n->next = t;
512				t = n;
513
514				n = xmalloc(sizeof(*n));
515				n->string = xstrdup("UNKNOWN");
516				n->tag = SYM_NORMAL;
517				n->next = t;
518				t = n;
519
520				n = xmalloc(sizeof(*n));
521				n->string = xstrdup("}");
522				n->tag = SYM_NORMAL;
523				n->next = t;
524				t = n;
525
526				subsym =
527				    add_symbol(cur->string, cur->tag, n, 0);
528			}
529			if (subsym->expansion_trail) {
530				if (flag_dump_defs) {
531					fprintf(debugfile, "%s %s ",
532						symbol_type_name[cur->tag],
533						cur->string);
534				}
535
536				crc = partial_crc32(symbol_type_name[cur->tag],
537						    crc);
538				crc = partial_crc32_one(' ', crc);
539				crc = partial_crc32(cur->string, crc);
540				crc = partial_crc32_one(' ', crc);
541			} else {
542				subsym->expansion_trail = expansion_trail;
543				expansion_trail = subsym;
544				crc = expand_and_crc_sym(subsym, crc);
545			}
546			break;
547		}
548	}
549
550	{
551		static struct symbol **end = &visited_symbols;
552
553		if (!sym->visited) {
554			*end = sym;
555			end = &sym->visited;
556			sym->visited = (struct symbol *)-1L;
557		}
558	}
559
560	return crc;
561}
562
563void export_symbol(const char *name)
564{
565	struct symbol *sym;
566
567	sym = find_symbol(name, SYM_NORMAL);
568	if (!sym)
569		error_with_pos("export undefined symbol %s", name);
570	else {
571		unsigned long crc;
572		int has_changed = 0;
573
574		if (flag_dump_defs)
575			fprintf(debugfile, "Export %s == <", name);
576
577		expansion_trail = (struct symbol *)-1L;
578
579		sym->expansion_trail = expansion_trail;
580		expansion_trail = sym;
581		crc = expand_and_crc_sym(sym, 0xffffffff) ^ 0xffffffff;
582
583		sym = expansion_trail;
584		while (sym != (struct symbol *)-1L) {
585			struct symbol *n = sym->expansion_trail;
586
587			if (sym->status != STATUS_UNCHANGED) {
588				if (!has_changed) {
589					print_location();
590					fprintf(stderr, "%s: %s: modversion "
591						"changed because of changes "
592						"in ", flag_preserve ? "error" :
593						       "warning", name);
594				} else
595					fprintf(stderr, ", ");
596				print_type_name(sym->type, sym->name);
597				if (sym->status == STATUS_DEFINED)
598					fprintf(stderr, " (became defined)");
599				has_changed = 1;
600				if (flag_preserve)
601					errors++;
602			}
603			sym->expansion_trail = 0;
604			sym = n;
605		}
606		if (has_changed)
607			fprintf(stderr, "\n");
608
609		if (flag_dump_defs)
610			fputs(">\n", debugfile);
611
612		/* Used as a linker script. */
613		printf("%s__crc_%s = 0x%08lx ;\n", mod_prefix, name, crc);
614	}
615}
616
617/*----------------------------------------------------------------------*/
618
619static void print_location(void)
620{
621	fprintf(stderr, "%s:%d: ", cur_filename ? : "<stdin>", cur_line);
622}
623
624static void print_type_name(enum symbol_type type, const char *name)
625{
626	if (type != SYM_NORMAL)
627		fprintf(stderr, "%s %s", symbol_type_name[type], name);
628	else
629		fprintf(stderr, "%s", name);
630}
631
632void error_with_pos(const char *fmt, ...)
633{
634	va_list args;
635
636	if (flag_warnings) {
637		print_location();
638
639		va_start(args, fmt);
640		vfprintf(stderr, fmt, args);
641		va_end(args);
642		putc('\n', stderr);
643
644		errors++;
645	}
646}
647
648static void genksyms_usage(void)
649{
650	fputs("Usage:\n" "genksyms [-adDTwqhV] > /path/to/.tmp_obj.ver\n" "\n"
651#ifdef __GNU_LIBRARY__
652	      "  -a, --arch            Select architecture\n"
653	      "  -d, --debug           Increment the debug level (repeatable)\n"
654	      "  -D, --dump            Dump expanded symbol defs (for debugging only)\n"
655	      "  -r, --reference file  Read reference symbols from a file\n"
656	      "  -T, --dump-types file Dump expanded types into file\n"
657	      "  -p, --preserve        Preserve reference modversions or fail\n"
658	      "  -w, --warnings        Enable warnings\n"
659	      "  -q, --quiet           Disable warnings (default)\n"
660	      "  -h, --help            Print this message\n"
661	      "  -V, --version         Print the release version\n"
662#else				/* __GNU_LIBRARY__ */
663	      "  -a                    Select architecture\n"
664	      "  -d                    Increment the debug level (repeatable)\n"
665	      "  -D                    Dump expanded symbol defs (for debugging only)\n"
666	      "  -r file               Read reference symbols from a file\n"
667	      "  -T file               Dump expanded types into file\n"
668	      "  -p                    Preserve reference modversions or fail\n"
669	      "  -w                    Enable warnings\n"
670	      "  -q                    Disable warnings (default)\n"
671	      "  -h                    Print this message\n"
672	      "  -V                    Print the release version\n"
673#endif				/* __GNU_LIBRARY__ */
674	      , stderr);
675}
676
677int main(int argc, char **argv)
678{
679	FILE *dumpfile = NULL, *ref_file = NULL;
680	int o;
681
682#ifdef __GNU_LIBRARY__
683	struct option long_opts[] = {
684		{"arch", 1, 0, 'a'},
685		{"debug", 0, 0, 'd'},
686		{"warnings", 0, 0, 'w'},
687		{"quiet", 0, 0, 'q'},
688		{"dump", 0, 0, 'D'},
689		{"reference", 1, 0, 'r'},
690		{"dump-types", 1, 0, 'T'},
691		{"preserve", 0, 0, 'p'},
692		{"version", 0, 0, 'V'},
693		{"help", 0, 0, 'h'},
694		{0, 0, 0, 0}
695	};
696
697	while ((o = getopt_long(argc, argv, "a:dwqVDr:T:ph",
698				&long_opts[0], NULL)) != EOF)
699#else				/* __GNU_LIBRARY__ */
700	while ((o = getopt(argc, argv, "a:dwqVDr:T:ph")) != EOF)
701#endif				/* __GNU_LIBRARY__ */
702		switch (o) {
703		case 'a':
704			arch = optarg;
705			break;
706		case 'd':
707			flag_debug++;
708			break;
709		case 'w':
710			flag_warnings = 1;
711			break;
712		case 'q':
713			flag_warnings = 0;
714			break;
715		case 'V':
716			fputs("genksyms version 2.5.60\n", stderr);
717			break;
718		case 'D':
719			flag_dump_defs = 1;
720			break;
721		case 'r':
722			flag_reference = 1;
723			ref_file = fopen(optarg, "r");
724			if (!ref_file) {
725				perror(optarg);
726				return 1;
727			}
728			break;
729		case 'T':
730			flag_dump_types = 1;
731			dumpfile = fopen(optarg, "w");
732			if (!dumpfile) {
733				perror(optarg);
734				return 1;
735			}
736			break;
737		case 'p':
738			flag_preserve = 1;
739			break;
740		case 'h':
741			genksyms_usage();
742			return 0;
743		default:
744			genksyms_usage();
745			return 1;
746		}
747	if ((strcmp(arch, "h8300") == 0) || (strcmp(arch, "blackfin") == 0))
748		mod_prefix = "_";
749	{
750		extern int yydebug;
751		extern int yy_flex_debug;
752
753		yydebug = (flag_debug > 1);
754		yy_flex_debug = (flag_debug > 2);
755
756		debugfile = stderr;
757		/* setlinebuf(debugfile); */
758	}
759
760	if (flag_reference) {
761		read_reference(ref_file);
762		fclose(ref_file);
763	}
764
765	yyparse();
766
767	if (flag_dump_types && visited_symbols) {
768		while (visited_symbols != (struct symbol *)-1L) {
769			struct symbol *sym = visited_symbols;
770
771			if (sym->is_override)
772				fputs("override ", dumpfile);
773			if (sym->type != SYM_NORMAL) {
774				putc(symbol_type_name[sym->type][0], dumpfile);
775				putc('#', dumpfile);
776			}
777			fputs(sym->name, dumpfile);
778			putc(' ', dumpfile);
779			if (sym->is_extern)
780				fputs("extern ", dumpfile);
781			print_list(dumpfile, sym->defn);
782			putc('\n', dumpfile);
783
784			visited_symbols = sym->visited;
785			sym->visited = NULL;
786		}
787	}
788
789	if (flag_debug) {
790		fprintf(debugfile, "Hash table occupancy %d/%d = %g\n",
791			nsyms, HASH_BUCKETS,
792			(double)nsyms / (double)HASH_BUCKETS);
793	}
794
795	return errors != 0;
796}
797