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