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