xref: /openbmc/linux/scripts/genksyms/genksyms.c (revision f0702555)
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 }
881