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