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 
partial_crc32_one(unsigned char c,unsigned long crc)118 static unsigned long partial_crc32_one(unsigned char c, unsigned long crc)
119 {
120 	return crctab32[(crc ^ c) & 0xff] ^ (crc >> 8);
121 }
122 
partial_crc32(const char * s,unsigned long crc)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 
crc32(const char * s)130 static unsigned long crc32(const char *s)
131 {
132 	return partial_crc32(s, 0xffffffff) ^ 0xffffffff;
133 }
134 
135 /*----------------------------------------------------------------------*/
136 
map_to_ns(enum symbol_type t)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 
find_symbol(const char * name,enum symbol_type ns,int exact)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 
is_unknown_symbol(struct symbol * sym)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 
__add_symbol(const char * name,enum symbol_type type,struct string_list * defn,int is_extern,int is_reference)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 				free_list(defn, NULL);
243 				return sym;
244 			} else if (!sym->is_declared) {
245 				if (sym->is_override && flag_preserve) {
246 					print_location();
247 					fprintf(stderr, "ignoring ");
248 					print_type_name(type, name);
249 					fprintf(stderr, " modversion change\n");
250 					sym->is_declared = 1;
251 					free_list(defn, NULL);
252 					return sym;
253 				} else {
254 					status = is_unknown_symbol(sym) ?
255 						STATUS_DEFINED : STATUS_MODIFIED;
256 				}
257 			} else {
258 				error_with_pos("redefinition of %s", name);
259 				free_list(defn, NULL);
260 				return sym;
261 			}
262 			break;
263 		}
264 	}
265 
266 	if (sym) {
267 		struct symbol **psym;
268 
269 		for (psym = &symtab[h]; *psym; psym = &(*psym)->hash_next) {
270 			if (*psym == sym) {
271 				*psym = sym->hash_next;
272 				break;
273 			}
274 		}
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 	sym->hash_next = symtab[h];
291 	symtab[h] = sym;
292 
293 	sym->is_declared = !is_reference;
294 	sym->status = status;
295 	sym->is_override = 0;
296 
297 	if (flag_debug) {
298 		if (symbol_types[type].name)
299 			fprintf(debugfile, "Defn for %s %s == <",
300 				symbol_types[type].name, name);
301 		else
302 			fprintf(debugfile, "Defn for type%d %s == <",
303 				type, name);
304 		if (is_extern)
305 			fputs("extern ", debugfile);
306 		print_list(debugfile, defn);
307 		fputs(">\n", debugfile);
308 	}
309 
310 	++nsyms;
311 	return sym;
312 }
313 
add_symbol(const char * name,enum symbol_type type,struct string_list * defn,int is_extern)314 struct symbol *add_symbol(const char *name, enum symbol_type type,
315 			  struct string_list *defn, int is_extern)
316 {
317 	return __add_symbol(name, type, defn, is_extern, 0);
318 }
319 
add_reference_symbol(const char * name,enum symbol_type type,struct string_list * defn,int is_extern)320 static struct symbol *add_reference_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, 1);
324 }
325 
326 /*----------------------------------------------------------------------*/
327 
free_node(struct string_list * node)328 void free_node(struct string_list *node)
329 {
330 	free(node->string);
331 	free(node);
332 }
333 
free_list(struct string_list * s,struct string_list * e)334 void free_list(struct string_list *s, struct string_list *e)
335 {
336 	while (s != e) {
337 		struct string_list *next = s->next;
338 		free_node(s);
339 		s = next;
340 	}
341 }
342 
mk_node(const char * string)343 static struct string_list *mk_node(const char *string)
344 {
345 	struct string_list *newnode;
346 
347 	newnode = xmalloc(sizeof(*newnode));
348 	newnode->string = xstrdup(string);
349 	newnode->tag = SYM_NORMAL;
350 	newnode->next = NULL;
351 
352 	return newnode;
353 }
354 
concat_list(struct string_list * start,...)355 static struct string_list *concat_list(struct string_list *start, ...)
356 {
357 	va_list ap;
358 	struct string_list *n, *n2;
359 
360 	if (!start)
361 		return NULL;
362 	for (va_start(ap, start); (n = va_arg(ap, struct string_list *));) {
363 		for (n2 = n; n2->next; n2 = n2->next)
364 			;
365 		n2->next = start;
366 		start = n;
367 	}
368 	va_end(ap);
369 	return start;
370 }
371 
copy_node(struct string_list * node)372 struct string_list *copy_node(struct string_list *node)
373 {
374 	struct string_list *newnode;
375 
376 	newnode = xmalloc(sizeof(*newnode));
377 	newnode->string = xstrdup(node->string);
378 	newnode->tag = node->tag;
379 
380 	return newnode;
381 }
382 
copy_list_range(struct string_list * start,struct string_list * end)383 struct string_list *copy_list_range(struct string_list *start,
384 				    struct string_list *end)
385 {
386 	struct string_list *res, *n;
387 
388 	if (start == end)
389 		return NULL;
390 	n = res = copy_node(start);
391 	for (start = start->next; start != end; start = start->next) {
392 		n->next = copy_node(start);
393 		n = n->next;
394 	}
395 	n->next = NULL;
396 	return res;
397 }
398 
equal_list(struct string_list * a,struct string_list * b)399 static int equal_list(struct string_list *a, struct string_list *b)
400 {
401 	while (a && b) {
402 		if (a->tag != b->tag || strcmp(a->string, b->string))
403 			return 0;
404 		a = a->next;
405 		b = b->next;
406 	}
407 
408 	return !a && !b;
409 }
410 
411 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
412 
read_node(FILE * f)413 static struct string_list *read_node(FILE *f)
414 {
415 	char buffer[256];
416 	struct string_list node = {
417 		.string = buffer,
418 		.tag = SYM_NORMAL };
419 	int c, in_string = 0;
420 
421 	while ((c = fgetc(f)) != EOF) {
422 		if (!in_string && c == ' ') {
423 			if (node.string == buffer)
424 				continue;
425 			break;
426 		} else if (c == '"') {
427 			in_string = !in_string;
428 		} else if (c == '\n') {
429 			if (node.string == buffer)
430 				return NULL;
431 			ungetc(c, f);
432 			break;
433 		}
434 		if (node.string >= buffer + sizeof(buffer) - 1) {
435 			fprintf(stderr, "Token too long\n");
436 			exit(1);
437 		}
438 		*node.string++ = c;
439 	}
440 	if (node.string == buffer)
441 		return NULL;
442 	*node.string = 0;
443 	node.string = buffer;
444 
445 	if (node.string[1] == '#') {
446 		size_t n;
447 
448 		for (n = 0; n < ARRAY_SIZE(symbol_types); n++) {
449 			if (node.string[0] == symbol_types[n].n) {
450 				node.tag = n;
451 				node.string += 2;
452 				return copy_node(&node);
453 			}
454 		}
455 		fprintf(stderr, "Unknown type %c\n", node.string[0]);
456 		exit(1);
457 	}
458 	return copy_node(&node);
459 }
460 
read_reference(FILE * f)461 static void read_reference(FILE *f)
462 {
463 	while (!feof(f)) {
464 		struct string_list *defn = NULL;
465 		struct string_list *sym, *def;
466 		int is_extern = 0, is_override = 0;
467 		struct symbol *subsym;
468 
469 		sym = read_node(f);
470 		if (sym && sym->tag == SYM_NORMAL &&
471 		    !strcmp(sym->string, "override")) {
472 			is_override = 1;
473 			free_node(sym);
474 			sym = read_node(f);
475 		}
476 		if (!sym)
477 			continue;
478 		def = read_node(f);
479 		if (def && def->tag == SYM_NORMAL &&
480 		    !strcmp(def->string, "extern")) {
481 			is_extern = 1;
482 			free_node(def);
483 			def = read_node(f);
484 		}
485 		while (def) {
486 			def->next = defn;
487 			defn = def;
488 			def = read_node(f);
489 		}
490 		subsym = add_reference_symbol(sym->string, sym->tag,
491 					      defn, is_extern);
492 		subsym->is_override = is_override;
493 		free_node(sym);
494 	}
495 }
496 
print_node(FILE * f,struct string_list * list)497 static void print_node(FILE * f, struct string_list *list)
498 {
499 	if (symbol_types[list->tag].n) {
500 		putc(symbol_types[list->tag].n, f);
501 		putc('#', f);
502 	}
503 	fputs(list->string, f);
504 }
505 
print_list(FILE * f,struct string_list * list)506 static void print_list(FILE * f, struct string_list *list)
507 {
508 	struct string_list **e, **b;
509 	struct string_list *tmp, **tmp2;
510 	int elem = 1;
511 
512 	if (list == NULL) {
513 		fputs("(nil)", f);
514 		return;
515 	}
516 
517 	tmp = list;
518 	while ((tmp = tmp->next) != NULL)
519 		elem++;
520 
521 	b = alloca(elem * sizeof(*e));
522 	e = b + elem;
523 	tmp2 = e - 1;
524 
525 	(*tmp2--) = list;
526 	while ((list = list->next) != NULL)
527 		*(tmp2--) = list;
528 
529 	while (b != e) {
530 		print_node(f, *b++);
531 		putc(' ', f);
532 	}
533 }
534 
expand_and_crc_sym(struct symbol * sym,unsigned long crc)535 static unsigned long expand_and_crc_sym(struct symbol *sym, unsigned long crc)
536 {
537 	struct string_list *list = sym->defn;
538 	struct string_list **e, **b;
539 	struct string_list *tmp, **tmp2;
540 	int elem = 1;
541 
542 	if (!list)
543 		return crc;
544 
545 	tmp = list;
546 	while ((tmp = tmp->next) != NULL)
547 		elem++;
548 
549 	b = alloca(elem * sizeof(*e));
550 	e = b + elem;
551 	tmp2 = e - 1;
552 
553 	*(tmp2--) = list;
554 	while ((list = list->next) != NULL)
555 		*(tmp2--) = list;
556 
557 	while (b != e) {
558 		struct string_list *cur;
559 		struct symbol *subsym;
560 
561 		cur = *(b++);
562 		switch (cur->tag) {
563 		case SYM_NORMAL:
564 			if (flag_dump_defs)
565 				fprintf(debugfile, "%s ", cur->string);
566 			crc = partial_crc32(cur->string, crc);
567 			crc = partial_crc32_one(' ', crc);
568 			break;
569 
570 		case SYM_ENUM_CONST:
571 		case SYM_TYPEDEF:
572 			subsym = find_symbol(cur->string, cur->tag, 0);
573 			/* FIXME: Bad reference files can segfault here. */
574 			if (subsym->expansion_trail) {
575 				if (flag_dump_defs)
576 					fprintf(debugfile, "%s ", cur->string);
577 				crc = partial_crc32(cur->string, crc);
578 				crc = partial_crc32_one(' ', crc);
579 			} else {
580 				subsym->expansion_trail = expansion_trail;
581 				expansion_trail = subsym;
582 				crc = expand_and_crc_sym(subsym, crc);
583 			}
584 			break;
585 
586 		case SYM_STRUCT:
587 		case SYM_UNION:
588 		case SYM_ENUM:
589 			subsym = find_symbol(cur->string, cur->tag, 0);
590 			if (!subsym) {
591 				struct string_list *n;
592 
593 				error_with_pos("expand undefined %s %s",
594 					       symbol_types[cur->tag].name,
595 					       cur->string);
596 				n = concat_list(mk_node
597 						(symbol_types[cur->tag].name),
598 						mk_node(cur->string),
599 						mk_node("{"),
600 						mk_node("UNKNOWN"),
601 						mk_node("}"), NULL);
602 				subsym =
603 				    add_symbol(cur->string, cur->tag, n, 0);
604 			}
605 			if (subsym->expansion_trail) {
606 				if (flag_dump_defs) {
607 					fprintf(debugfile, "%s %s ",
608 						symbol_types[cur->tag].name,
609 						cur->string);
610 				}
611 
612 				crc = partial_crc32(symbol_types[cur->tag].name,
613 						    crc);
614 				crc = partial_crc32_one(' ', crc);
615 				crc = partial_crc32(cur->string, crc);
616 				crc = partial_crc32_one(' ', crc);
617 			} else {
618 				subsym->expansion_trail = expansion_trail;
619 				expansion_trail = subsym;
620 				crc = expand_and_crc_sym(subsym, crc);
621 			}
622 			break;
623 		}
624 	}
625 
626 	{
627 		static struct symbol **end = &visited_symbols;
628 
629 		if (!sym->visited) {
630 			*end = sym;
631 			end = &sym->visited;
632 			sym->visited = (struct symbol *)-1L;
633 		}
634 	}
635 
636 	return crc;
637 }
638 
export_symbol(const char * name)639 void export_symbol(const char *name)
640 {
641 	struct symbol *sym;
642 
643 	sym = find_symbol(name, SYM_NORMAL, 0);
644 	if (!sym)
645 		error_with_pos("export undefined symbol %s", name);
646 	else {
647 		unsigned long crc;
648 		int has_changed = 0;
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, "%s: %s: modversion "
667 						"changed because of changes "
668 						"in ", flag_preserve ? "error" :
669 						       "warning", name);
670 				} else
671 					fprintf(stderr, ", ");
672 				print_type_name(sym->type, sym->name);
673 				if (sym->status == STATUS_DEFINED)
674 					fprintf(stderr, " (became defined)");
675 				has_changed = 1;
676 				if (flag_preserve)
677 					errors++;
678 			}
679 			sym->expansion_trail = 0;
680 			sym = n;
681 		}
682 		if (has_changed)
683 			fprintf(stderr, "\n");
684 
685 		if (flag_dump_defs)
686 			fputs(">\n", debugfile);
687 
688 		printf("#SYMVER %s 0x%08lx\n", name, crc);
689 	}
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/%d = %g\n",
842 			nsyms, HASH_BUCKETS,
843 			(double)nsyms / (double)HASH_BUCKETS);
844 	}
845 
846 	if (dumpfile)
847 		fclose(dumpfile);
848 
849 	return errors != 0;
850 }
851