xref: /linux/scripts/genksyms/genksyms.c (revision 6e7fd890f1d6ac83805409e9c346240de2705584)
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 				return sym;
243 			} else if (!sym->is_declared) {
244 				if (sym->is_override && flag_preserve) {
245 					print_location();
246 					fprintf(stderr, "ignoring ");
247 					print_type_name(type, name);
248 					fprintf(stderr, " modversion change\n");
249 					sym->is_declared = 1;
250 					return sym;
251 				} else {
252 					status = is_unknown_symbol(sym) ?
253 						STATUS_DEFINED : STATUS_MODIFIED;
254 				}
255 			} else {
256 				error_with_pos("redefinition of %s", name);
257 				return sym;
258 			}
259 			break;
260 		}
261 	}
262 
263 	if (sym) {
264 		struct symbol **psym;
265 
266 		for (psym = &symtab[h]; *psym; psym = &(*psym)->hash_next) {
267 			if (*psym == sym) {
268 				*psym = sym->hash_next;
269 				break;
270 			}
271 		}
272 		--nsyms;
273 	}
274 
275 	sym = xmalloc(sizeof(*sym));
276 	sym->name = name;
277 	sym->type = type;
278 	sym->defn = defn;
279 	sym->expansion_trail = NULL;
280 	sym->visited = NULL;
281 	sym->is_extern = is_extern;
282 
283 	sym->hash_next = symtab[h];
284 	symtab[h] = sym;
285 
286 	sym->is_declared = !is_reference;
287 	sym->status = status;
288 	sym->is_override = 0;
289 
290 	if (flag_debug) {
291 		if (symbol_types[type].name)
292 			fprintf(debugfile, "Defn for %s %s == <",
293 				symbol_types[type].name, name);
294 		else
295 			fprintf(debugfile, "Defn for type%d %s == <",
296 				type, name);
297 		if (is_extern)
298 			fputs("extern ", debugfile);
299 		print_list(debugfile, defn);
300 		fputs(">\n", debugfile);
301 	}
302 
303 	++nsyms;
304 	return sym;
305 }
306 
307 struct symbol *add_symbol(const char *name, enum symbol_type type,
308 			  struct string_list *defn, int is_extern)
309 {
310 	return __add_symbol(name, type, defn, is_extern, 0);
311 }
312 
313 static struct symbol *add_reference_symbol(const char *name, enum symbol_type type,
314 				    struct string_list *defn, int is_extern)
315 {
316 	return __add_symbol(name, type, defn, is_extern, 1);
317 }
318 
319 /*----------------------------------------------------------------------*/
320 
321 void free_node(struct string_list *node)
322 {
323 	free(node->string);
324 	free(node);
325 }
326 
327 void free_list(struct string_list *s, struct string_list *e)
328 {
329 	while (s != e) {
330 		struct string_list *next = s->next;
331 		free_node(s);
332 		s = next;
333 	}
334 }
335 
336 static struct string_list *mk_node(const char *string)
337 {
338 	struct string_list *newnode;
339 
340 	newnode = xmalloc(sizeof(*newnode));
341 	newnode->string = xstrdup(string);
342 	newnode->tag = SYM_NORMAL;
343 	newnode->next = NULL;
344 
345 	return newnode;
346 }
347 
348 static struct string_list *concat_list(struct string_list *start, ...)
349 {
350 	va_list ap;
351 	struct string_list *n, *n2;
352 
353 	if (!start)
354 		return NULL;
355 	for (va_start(ap, start); (n = va_arg(ap, struct string_list *));) {
356 		for (n2 = n; n2->next; n2 = n2->next)
357 			;
358 		n2->next = start;
359 		start = n;
360 	}
361 	va_end(ap);
362 	return start;
363 }
364 
365 struct string_list *copy_node(struct string_list *node)
366 {
367 	struct string_list *newnode;
368 
369 	newnode = xmalloc(sizeof(*newnode));
370 	newnode->string = xstrdup(node->string);
371 	newnode->tag = node->tag;
372 
373 	return newnode;
374 }
375 
376 struct string_list *copy_list_range(struct string_list *start,
377 				    struct string_list *end)
378 {
379 	struct string_list *res, *n;
380 
381 	if (start == end)
382 		return NULL;
383 	n = res = copy_node(start);
384 	for (start = start->next; start != end; start = start->next) {
385 		n->next = copy_node(start);
386 		n = n->next;
387 	}
388 	n->next = NULL;
389 	return res;
390 }
391 
392 static int equal_list(struct string_list *a, struct string_list *b)
393 {
394 	while (a && b) {
395 		if (a->tag != b->tag || strcmp(a->string, b->string))
396 			return 0;
397 		a = a->next;
398 		b = b->next;
399 	}
400 
401 	return !a && !b;
402 }
403 
404 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
405 
406 static struct string_list *read_node(FILE *f)
407 {
408 	char buffer[256];
409 	struct string_list node = {
410 		.string = buffer,
411 		.tag = SYM_NORMAL };
412 	int c, in_string = 0;
413 
414 	while ((c = fgetc(f)) != EOF) {
415 		if (!in_string && c == ' ') {
416 			if (node.string == buffer)
417 				continue;
418 			break;
419 		} else if (c == '"') {
420 			in_string = !in_string;
421 		} else if (c == '\n') {
422 			if (node.string == buffer)
423 				return NULL;
424 			ungetc(c, f);
425 			break;
426 		}
427 		if (node.string >= buffer + sizeof(buffer) - 1) {
428 			fprintf(stderr, "Token too long\n");
429 			exit(1);
430 		}
431 		*node.string++ = c;
432 	}
433 	if (node.string == buffer)
434 		return NULL;
435 	*node.string = 0;
436 	node.string = buffer;
437 
438 	if (node.string[1] == '#') {
439 		size_t n;
440 
441 		for (n = 0; n < ARRAY_SIZE(symbol_types); n++) {
442 			if (node.string[0] == symbol_types[n].n) {
443 				node.tag = n;
444 				node.string += 2;
445 				return copy_node(&node);
446 			}
447 		}
448 		fprintf(stderr, "Unknown type %c\n", node.string[0]);
449 		exit(1);
450 	}
451 	return copy_node(&node);
452 }
453 
454 static void read_reference(FILE *f)
455 {
456 	while (!feof(f)) {
457 		struct string_list *defn = NULL;
458 		struct string_list *sym, *def;
459 		int is_extern = 0, is_override = 0;
460 		struct symbol *subsym;
461 
462 		sym = read_node(f);
463 		if (sym && sym->tag == SYM_NORMAL &&
464 		    !strcmp(sym->string, "override")) {
465 			is_override = 1;
466 			free_node(sym);
467 			sym = read_node(f);
468 		}
469 		if (!sym)
470 			continue;
471 		def = read_node(f);
472 		if (def && def->tag == SYM_NORMAL &&
473 		    !strcmp(def->string, "extern")) {
474 			is_extern = 1;
475 			free_node(def);
476 			def = read_node(f);
477 		}
478 		while (def) {
479 			def->next = defn;
480 			defn = def;
481 			def = read_node(f);
482 		}
483 		subsym = add_reference_symbol(xstrdup(sym->string), sym->tag,
484 					      defn, is_extern);
485 		subsym->is_override = is_override;
486 		free_node(sym);
487 	}
488 }
489 
490 static void print_node(FILE * f, struct string_list *list)
491 {
492 	if (symbol_types[list->tag].n) {
493 		putc(symbol_types[list->tag].n, f);
494 		putc('#', f);
495 	}
496 	fputs(list->string, f);
497 }
498 
499 static void print_list(FILE * f, struct string_list *list)
500 {
501 	struct string_list **e, **b;
502 	struct string_list *tmp, **tmp2;
503 	int elem = 1;
504 
505 	if (list == NULL) {
506 		fputs("(nil)", f);
507 		return;
508 	}
509 
510 	tmp = list;
511 	while ((tmp = tmp->next) != NULL)
512 		elem++;
513 
514 	b = alloca(elem * sizeof(*e));
515 	e = b + elem;
516 	tmp2 = e - 1;
517 
518 	(*tmp2--) = list;
519 	while ((list = list->next) != NULL)
520 		*(tmp2--) = list;
521 
522 	while (b != e) {
523 		print_node(f, *b++);
524 		putc(' ', f);
525 	}
526 }
527 
528 static unsigned long expand_and_crc_sym(struct symbol *sym, unsigned long crc)
529 {
530 	struct string_list *list = sym->defn;
531 	struct string_list **e, **b;
532 	struct string_list *tmp, **tmp2;
533 	int elem = 1;
534 
535 	if (!list)
536 		return crc;
537 
538 	tmp = list;
539 	while ((tmp = tmp->next) != NULL)
540 		elem++;
541 
542 	b = alloca(elem * sizeof(*e));
543 	e = b + elem;
544 	tmp2 = e - 1;
545 
546 	*(tmp2--) = list;
547 	while ((list = list->next) != NULL)
548 		*(tmp2--) = list;
549 
550 	while (b != e) {
551 		struct string_list *cur;
552 		struct symbol *subsym;
553 
554 		cur = *(b++);
555 		switch (cur->tag) {
556 		case SYM_NORMAL:
557 			if (flag_dump_defs)
558 				fprintf(debugfile, "%s ", cur->string);
559 			crc = partial_crc32(cur->string, crc);
560 			crc = partial_crc32_one(' ', crc);
561 			break;
562 
563 		case SYM_ENUM_CONST:
564 		case SYM_TYPEDEF:
565 			subsym = find_symbol(cur->string, cur->tag, 0);
566 			/* FIXME: Bad reference files can segfault here. */
567 			if (subsym->expansion_trail) {
568 				if (flag_dump_defs)
569 					fprintf(debugfile, "%s ", cur->string);
570 				crc = partial_crc32(cur->string, crc);
571 				crc = partial_crc32_one(' ', crc);
572 			} else {
573 				subsym->expansion_trail = expansion_trail;
574 				expansion_trail = subsym;
575 				crc = expand_and_crc_sym(subsym, crc);
576 			}
577 			break;
578 
579 		case SYM_STRUCT:
580 		case SYM_UNION:
581 		case SYM_ENUM:
582 			subsym = find_symbol(cur->string, cur->tag, 0);
583 			if (!subsym) {
584 				struct string_list *n;
585 
586 				error_with_pos("expand undefined %s %s",
587 					       symbol_types[cur->tag].name,
588 					       cur->string);
589 				n = concat_list(mk_node
590 						(symbol_types[cur->tag].name),
591 						mk_node(cur->string),
592 						mk_node("{"),
593 						mk_node("UNKNOWN"),
594 						mk_node("}"), NULL);
595 				subsym =
596 				    add_symbol(cur->string, cur->tag, n, 0);
597 			}
598 			if (subsym->expansion_trail) {
599 				if (flag_dump_defs) {
600 					fprintf(debugfile, "%s %s ",
601 						symbol_types[cur->tag].name,
602 						cur->string);
603 				}
604 
605 				crc = partial_crc32(symbol_types[cur->tag].name,
606 						    crc);
607 				crc = partial_crc32_one(' ', crc);
608 				crc = partial_crc32(cur->string, crc);
609 				crc = partial_crc32_one(' ', crc);
610 			} else {
611 				subsym->expansion_trail = expansion_trail;
612 				expansion_trail = subsym;
613 				crc = expand_and_crc_sym(subsym, crc);
614 			}
615 			break;
616 		}
617 	}
618 
619 	{
620 		static struct symbol **end = &visited_symbols;
621 
622 		if (!sym->visited) {
623 			*end = sym;
624 			end = &sym->visited;
625 			sym->visited = (struct symbol *)-1L;
626 		}
627 	}
628 
629 	return crc;
630 }
631 
632 void export_symbol(const char *name)
633 {
634 	struct symbol *sym;
635 
636 	sym = find_symbol(name, SYM_NORMAL, 0);
637 	if (!sym)
638 		error_with_pos("export undefined symbol %s", name);
639 	else {
640 		unsigned long crc;
641 		int has_changed = 0;
642 
643 		if (flag_dump_defs)
644 			fprintf(debugfile, "Export %s == <", name);
645 
646 		expansion_trail = (struct symbol *)-1L;
647 
648 		sym->expansion_trail = expansion_trail;
649 		expansion_trail = sym;
650 		crc = expand_and_crc_sym(sym, 0xffffffff) ^ 0xffffffff;
651 
652 		sym = expansion_trail;
653 		while (sym != (struct symbol *)-1L) {
654 			struct symbol *n = sym->expansion_trail;
655 
656 			if (sym->status != STATUS_UNCHANGED) {
657 				if (!has_changed) {
658 					print_location();
659 					fprintf(stderr, "%s: %s: modversion "
660 						"changed because of changes "
661 						"in ", flag_preserve ? "error" :
662 						       "warning", name);
663 				} else
664 					fprintf(stderr, ", ");
665 				print_type_name(sym->type, sym->name);
666 				if (sym->status == STATUS_DEFINED)
667 					fprintf(stderr, " (became defined)");
668 				has_changed = 1;
669 				if (flag_preserve)
670 					errors++;
671 			}
672 			sym->expansion_trail = 0;
673 			sym = n;
674 		}
675 		if (has_changed)
676 			fprintf(stderr, "\n");
677 
678 		if (flag_dump_defs)
679 			fputs(">\n", debugfile);
680 
681 		printf("#SYMVER %s 0x%08lx\n", name, crc);
682 	}
683 }
684 
685 /*----------------------------------------------------------------------*/
686 
687 static void print_location(void)
688 {
689 	fprintf(stderr, "%s:%d: ", cur_filename ? : "<stdin>", cur_line);
690 }
691 
692 static void print_type_name(enum symbol_type type, const char *name)
693 {
694 	if (symbol_types[type].name)
695 		fprintf(stderr, "%s %s", symbol_types[type].name, name);
696 	else
697 		fprintf(stderr, "%s", name);
698 }
699 
700 void error_with_pos(const char *fmt, ...)
701 {
702 	va_list args;
703 
704 	if (flag_warnings) {
705 		print_location();
706 
707 		va_start(args, fmt);
708 		vfprintf(stderr, fmt, args);
709 		va_end(args);
710 		putc('\n', stderr);
711 
712 		errors++;
713 	}
714 }
715 
716 static void genksyms_usage(void)
717 {
718 	fputs("Usage:\n" "genksyms [-adDTwqhVR] > /path/to/.tmp_obj.ver\n" "\n"
719 	      "  -d, --debug           Increment the debug level (repeatable)\n"
720 	      "  -D, --dump            Dump expanded symbol defs (for debugging only)\n"
721 	      "  -r, --reference file  Read reference symbols from a file\n"
722 	      "  -T, --dump-types file Dump expanded types into file\n"
723 	      "  -p, --preserve        Preserve reference modversions or fail\n"
724 	      "  -w, --warnings        Enable warnings\n"
725 	      "  -q, --quiet           Disable warnings (default)\n"
726 	      "  -h, --help            Print this message\n"
727 	      "  -V, --version         Print the release version\n"
728 	      , stderr);
729 }
730 
731 int main(int argc, char **argv)
732 {
733 	FILE *dumpfile = NULL, *ref_file = NULL;
734 	int o;
735 
736 	struct option long_opts[] = {
737 		{"debug", 0, 0, 'd'},
738 		{"warnings", 0, 0, 'w'},
739 		{"quiet", 0, 0, 'q'},
740 		{"dump", 0, 0, 'D'},
741 		{"reference", 1, 0, 'r'},
742 		{"dump-types", 1, 0, 'T'},
743 		{"preserve", 0, 0, 'p'},
744 		{"version", 0, 0, 'V'},
745 		{"help", 0, 0, 'h'},
746 		{0, 0, 0, 0}
747 	};
748 
749 	while ((o = getopt_long(argc, argv, "dwqVDr:T:ph",
750 				&long_opts[0], NULL)) != EOF)
751 		switch (o) {
752 		case 'd':
753 			flag_debug++;
754 			break;
755 		case 'w':
756 			flag_warnings = 1;
757 			break;
758 		case 'q':
759 			flag_warnings = 0;
760 			break;
761 		case 'V':
762 			fputs("genksyms version 2.5.60\n", stderr);
763 			break;
764 		case 'D':
765 			flag_dump_defs = 1;
766 			break;
767 		case 'r':
768 			flag_reference = 1;
769 			ref_file = fopen(optarg, "r");
770 			if (!ref_file) {
771 				perror(optarg);
772 				return 1;
773 			}
774 			break;
775 		case 'T':
776 			flag_dump_types = 1;
777 			dumpfile = fopen(optarg, "w");
778 			if (!dumpfile) {
779 				perror(optarg);
780 				return 1;
781 			}
782 			break;
783 		case 'p':
784 			flag_preserve = 1;
785 			break;
786 		case 'h':
787 			genksyms_usage();
788 			return 0;
789 		default:
790 			genksyms_usage();
791 			return 1;
792 		}
793 	{
794 		extern int yydebug;
795 		extern int yy_flex_debug;
796 
797 		yydebug = (flag_debug > 1);
798 		yy_flex_debug = (flag_debug > 2);
799 
800 		debugfile = stderr;
801 		/* setlinebuf(debugfile); */
802 	}
803 
804 	if (flag_reference) {
805 		read_reference(ref_file);
806 		fclose(ref_file);
807 	}
808 
809 	yyparse();
810 
811 	if (flag_dump_types && visited_symbols) {
812 		while (visited_symbols != (struct symbol *)-1L) {
813 			struct symbol *sym = visited_symbols;
814 
815 			if (sym->is_override)
816 				fputs("override ", dumpfile);
817 			if (symbol_types[sym->type].n) {
818 				putc(symbol_types[sym->type].n, dumpfile);
819 				putc('#', dumpfile);
820 			}
821 			fputs(sym->name, dumpfile);
822 			putc(' ', dumpfile);
823 			if (sym->is_extern)
824 				fputs("extern ", dumpfile);
825 			print_list(dumpfile, sym->defn);
826 			putc('\n', dumpfile);
827 
828 			visited_symbols = sym->visited;
829 			sym->visited = NULL;
830 		}
831 	}
832 
833 	if (flag_debug) {
834 		fprintf(debugfile, "Hash table occupancy %d/%d = %g\n",
835 			nsyms, HASH_BUCKETS,
836 			(double)nsyms / (double)HASH_BUCKETS);
837 	}
838 
839 	if (dumpfile)
840 		fclose(dumpfile);
841 
842 	return errors != 0;
843 }
844