xref: /linux/scripts/genksyms/genksyms.c (revision 7f71507851fc7764b36a3221839607d3a45c2025)
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 	unsigned long crc;
636 	int has_changed = 0;
637 
638 	sym = find_symbol(name, SYM_NORMAL, 0);
639 	if (!sym) {
640 		error_with_pos("export undefined symbol %s", name);
641 		return;
642 	}
643 
644 	if (flag_dump_defs)
645 		fprintf(debugfile, "Export %s == <", name);
646 
647 	expansion_trail = (struct symbol *)-1L;
648 
649 	sym->expansion_trail = expansion_trail;
650 	expansion_trail = sym;
651 	crc = expand_and_crc_sym(sym, 0xffffffff) ^ 0xffffffff;
652 
653 	sym = expansion_trail;
654 	while (sym != (struct symbol *)-1L) {
655 		struct symbol *n = sym->expansion_trail;
656 
657 		if (sym->status != STATUS_UNCHANGED) {
658 			if (!has_changed) {
659 				print_location();
660 				fprintf(stderr,
661 					"%s: %s: modversion changed because of changes in ",
662 					flag_preserve ? "error" : "warning",
663 					name);
664 			} else {
665 				fprintf(stderr, ", ");
666 			}
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 static void print_location(void)
689 {
690 	fprintf(stderr, "%s:%d: ", cur_filename ? : "<stdin>", cur_line);
691 }
692 
693 static void print_type_name(enum symbol_type type, const char *name)
694 {
695 	if (symbol_types[type].name)
696 		fprintf(stderr, "%s %s", symbol_types[type].name, name);
697 	else
698 		fprintf(stderr, "%s", name);
699 }
700 
701 void error_with_pos(const char *fmt, ...)
702 {
703 	va_list args;
704 
705 	if (flag_warnings) {
706 		print_location();
707 
708 		va_start(args, fmt);
709 		vfprintf(stderr, fmt, args);
710 		va_end(args);
711 		putc('\n', stderr);
712 
713 		errors++;
714 	}
715 }
716 
717 static void genksyms_usage(void)
718 {
719 	fputs("Usage:\n" "genksyms [-adDTwqhVR] > /path/to/.tmp_obj.ver\n" "\n"
720 	      "  -d, --debug           Increment the debug level (repeatable)\n"
721 	      "  -D, --dump            Dump expanded symbol defs (for debugging only)\n"
722 	      "  -r, --reference file  Read reference symbols from a file\n"
723 	      "  -T, --dump-types file Dump expanded types into file\n"
724 	      "  -p, --preserve        Preserve reference modversions or fail\n"
725 	      "  -w, --warnings        Enable warnings\n"
726 	      "  -q, --quiet           Disable warnings (default)\n"
727 	      "  -h, --help            Print this message\n"
728 	      "  -V, --version         Print the release version\n"
729 	      , stderr);
730 }
731 
732 int main(int argc, char **argv)
733 {
734 	FILE *dumpfile = NULL, *ref_file = NULL;
735 	int o;
736 
737 	struct option long_opts[] = {
738 		{"debug", 0, 0, 'd'},
739 		{"warnings", 0, 0, 'w'},
740 		{"quiet", 0, 0, 'q'},
741 		{"dump", 0, 0, 'D'},
742 		{"reference", 1, 0, 'r'},
743 		{"dump-types", 1, 0, 'T'},
744 		{"preserve", 0, 0, 'p'},
745 		{"version", 0, 0, 'V'},
746 		{"help", 0, 0, 'h'},
747 		{0, 0, 0, 0}
748 	};
749 
750 	while ((o = getopt_long(argc, argv, "dwqVDr:T:ph",
751 				&long_opts[0], NULL)) != EOF)
752 		switch (o) {
753 		case 'd':
754 			flag_debug++;
755 			break;
756 		case 'w':
757 			flag_warnings = 1;
758 			break;
759 		case 'q':
760 			flag_warnings = 0;
761 			break;
762 		case 'V':
763 			fputs("genksyms version 2.5.60\n", stderr);
764 			break;
765 		case 'D':
766 			flag_dump_defs = 1;
767 			break;
768 		case 'r':
769 			flag_reference = 1;
770 			ref_file = fopen(optarg, "r");
771 			if (!ref_file) {
772 				perror(optarg);
773 				return 1;
774 			}
775 			break;
776 		case 'T':
777 			flag_dump_types = 1;
778 			dumpfile = fopen(optarg, "w");
779 			if (!dumpfile) {
780 				perror(optarg);
781 				return 1;
782 			}
783 			break;
784 		case 'p':
785 			flag_preserve = 1;
786 			break;
787 		case 'h':
788 			genksyms_usage();
789 			return 0;
790 		default:
791 			genksyms_usage();
792 			return 1;
793 		}
794 	{
795 		extern int yydebug;
796 		extern int yy_flex_debug;
797 
798 		yydebug = (flag_debug > 1);
799 		yy_flex_debug = (flag_debug > 2);
800 
801 		debugfile = stderr;
802 		/* setlinebuf(debugfile); */
803 	}
804 
805 	if (flag_reference) {
806 		read_reference(ref_file);
807 		fclose(ref_file);
808 	}
809 
810 	yyparse();
811 
812 	if (flag_dump_types && visited_symbols) {
813 		while (visited_symbols != (struct symbol *)-1L) {
814 			struct symbol *sym = visited_symbols;
815 
816 			if (sym->is_override)
817 				fputs("override ", dumpfile);
818 			if (symbol_types[sym->type].n) {
819 				putc(symbol_types[sym->type].n, dumpfile);
820 				putc('#', dumpfile);
821 			}
822 			fputs(sym->name, dumpfile);
823 			putc(' ', dumpfile);
824 			if (sym->is_extern)
825 				fputs("extern ", dumpfile);
826 			print_list(dumpfile, sym->defn);
827 			putc('\n', dumpfile);
828 
829 			visited_symbols = sym->visited;
830 			sym->visited = NULL;
831 		}
832 	}
833 
834 	if (flag_debug) {
835 		fprintf(debugfile, "Hash table occupancy %d/%d = %g\n",
836 			nsyms, HASH_BUCKETS,
837 			(double)nsyms / (double)HASH_BUCKETS);
838 	}
839 
840 	if (dumpfile)
841 		fclose(dumpfile);
842 
843 	return errors != 0;
844 }
845