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