xref: /openbmc/linux/scripts/genksyms/genksyms.c (revision 3a83e4e6)
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, *source_file;
33 int in_source_file;
34 
35 static int flag_debug, flag_dump_defs, flag_reference, flag_dump_types,
36 	   flag_preserve, flag_warnings, flag_rel_crcs;
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 		/* Used as a linker script. */
684 		printf(!flag_rel_crcs ? "__crc_%s = 0x%08lx;\n" :
685 		       "SECTIONS { .rodata : ALIGN(4) { "
686 		       "__crc_%s = .; LONG(0x%08lx); } }\n",
687 		       name, crc);
688 	}
689 }
690 
691 /*----------------------------------------------------------------------*/
692 
693 static void print_location(void)
694 {
695 	fprintf(stderr, "%s:%d: ", cur_filename ? : "<stdin>", cur_line);
696 }
697 
698 static void print_type_name(enum symbol_type type, const char *name)
699 {
700 	if (symbol_types[type].name)
701 		fprintf(stderr, "%s %s", symbol_types[type].name, name);
702 	else
703 		fprintf(stderr, "%s", name);
704 }
705 
706 void error_with_pos(const char *fmt, ...)
707 {
708 	va_list args;
709 
710 	if (flag_warnings) {
711 		print_location();
712 
713 		va_start(args, fmt);
714 		vfprintf(stderr, fmt, args);
715 		va_end(args);
716 		putc('\n', stderr);
717 
718 		errors++;
719 	}
720 }
721 
722 static void genksyms_usage(void)
723 {
724 	fputs("Usage:\n" "genksyms [-adDTwqhVR] > /path/to/.tmp_obj.ver\n" "\n"
725 #ifdef __GNU_LIBRARY__
726 	      "  -s, --symbol-prefix   Select symbol prefix\n"
727 	      "  -d, --debug           Increment the debug level (repeatable)\n"
728 	      "  -D, --dump            Dump expanded symbol defs (for debugging only)\n"
729 	      "  -r, --reference file  Read reference symbols from a file\n"
730 	      "  -T, --dump-types file Dump expanded types into file\n"
731 	      "  -p, --preserve        Preserve reference modversions or fail\n"
732 	      "  -w, --warnings        Enable warnings\n"
733 	      "  -q, --quiet           Disable warnings (default)\n"
734 	      "  -h, --help            Print this message\n"
735 	      "  -V, --version         Print the release version\n"
736 	      "  -R, --relative-crc    Emit section relative symbol CRCs\n"
737 #else				/* __GNU_LIBRARY__ */
738 	      "  -s                    Select symbol prefix\n"
739 	      "  -d                    Increment the debug level (repeatable)\n"
740 	      "  -D                    Dump expanded symbol defs (for debugging only)\n"
741 	      "  -r file               Read reference symbols from a file\n"
742 	      "  -T file               Dump expanded types into file\n"
743 	      "  -p                    Preserve reference modversions or fail\n"
744 	      "  -w                    Enable warnings\n"
745 	      "  -q                    Disable warnings (default)\n"
746 	      "  -h                    Print this message\n"
747 	      "  -V                    Print the release version\n"
748 	      "  -R                    Emit section relative symbol CRCs\n"
749 #endif				/* __GNU_LIBRARY__ */
750 	      , stderr);
751 }
752 
753 int main(int argc, char **argv)
754 {
755 	FILE *dumpfile = NULL, *ref_file = NULL;
756 	int o;
757 
758 #ifdef __GNU_LIBRARY__
759 	struct option long_opts[] = {
760 		{"debug", 0, 0, 'd'},
761 		{"warnings", 0, 0, 'w'},
762 		{"quiet", 0, 0, 'q'},
763 		{"dump", 0, 0, 'D'},
764 		{"reference", 1, 0, 'r'},
765 		{"dump-types", 1, 0, 'T'},
766 		{"preserve", 0, 0, 'p'},
767 		{"version", 0, 0, 'V'},
768 		{"help", 0, 0, 'h'},
769 		{"relative-crc", 0, 0, 'R'},
770 		{0, 0, 0, 0}
771 	};
772 
773 	while ((o = getopt_long(argc, argv, "s:dwqVDr:T:phR",
774 				&long_opts[0], NULL)) != EOF)
775 #else				/* __GNU_LIBRARY__ */
776 	while ((o = getopt(argc, argv, "s:dwqVDr:T:phR")) != EOF)
777 #endif				/* __GNU_LIBRARY__ */
778 		switch (o) {
779 		case 'd':
780 			flag_debug++;
781 			break;
782 		case 'w':
783 			flag_warnings = 1;
784 			break;
785 		case 'q':
786 			flag_warnings = 0;
787 			break;
788 		case 'V':
789 			fputs("genksyms version 2.5.60\n", stderr);
790 			break;
791 		case 'D':
792 			flag_dump_defs = 1;
793 			break;
794 		case 'r':
795 			flag_reference = 1;
796 			ref_file = fopen(optarg, "r");
797 			if (!ref_file) {
798 				perror(optarg);
799 				return 1;
800 			}
801 			break;
802 		case 'T':
803 			flag_dump_types = 1;
804 			dumpfile = fopen(optarg, "w");
805 			if (!dumpfile) {
806 				perror(optarg);
807 				return 1;
808 			}
809 			break;
810 		case 'p':
811 			flag_preserve = 1;
812 			break;
813 		case 'h':
814 			genksyms_usage();
815 			return 0;
816 		case 'R':
817 			flag_rel_crcs = 1;
818 			break;
819 		default:
820 			genksyms_usage();
821 			return 1;
822 		}
823 	{
824 		extern int yydebug;
825 		extern int yy_flex_debug;
826 
827 		yydebug = (flag_debug > 1);
828 		yy_flex_debug = (flag_debug > 2);
829 
830 		debugfile = stderr;
831 		/* setlinebuf(debugfile); */
832 	}
833 
834 	if (flag_reference) {
835 		read_reference(ref_file);
836 		fclose(ref_file);
837 	}
838 
839 	yyparse();
840 
841 	if (flag_dump_types && visited_symbols) {
842 		while (visited_symbols != (struct symbol *)-1L) {
843 			struct symbol *sym = visited_symbols;
844 
845 			if (sym->is_override)
846 				fputs("override ", dumpfile);
847 			if (symbol_types[sym->type].n) {
848 				putc(symbol_types[sym->type].n, dumpfile);
849 				putc('#', dumpfile);
850 			}
851 			fputs(sym->name, dumpfile);
852 			putc(' ', dumpfile);
853 			if (sym->is_extern)
854 				fputs("extern ", dumpfile);
855 			print_list(dumpfile, sym->defn);
856 			putc('\n', dumpfile);
857 
858 			visited_symbols = sym->visited;
859 			sym->visited = NULL;
860 		}
861 	}
862 
863 	if (flag_debug) {
864 		fprintf(debugfile, "Hash table occupancy %d/%d = %g\n",
865 			nsyms, HASH_BUCKETS,
866 			(double)nsyms / (double)HASH_BUCKETS);
867 	}
868 
869 	if (dumpfile)
870 		fclose(dumpfile);
871 
872 	return errors != 0;
873 }
874