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