xref: /linux/scripts/genksyms/genksyms.c (revision ba6ec09911b805778a2fed6d626bfe77b011a717)
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 
__add_symbol(const char * name,enum symbol_type type,struct string_list * defn,int is_extern,int is_reference)184 static struct symbol *__add_symbol(const char *name, enum symbol_type type,
185 			    struct string_list *defn, int is_extern,
186 			    int is_reference)
187 {
188 	unsigned long h;
189 	struct symbol *sym;
190 	enum symbol_status status = STATUS_UNCHANGED;
191 	/* The parser adds symbols in the order their declaration completes,
192 	 * so it is safe to store the value of the previous enum constant in
193 	 * a static variable.
194 	 */
195 	static int enum_counter;
196 	static struct string_list *last_enum_expr;
197 
198 	if (type == SYM_ENUM_CONST) {
199 		if (defn) {
200 			free_list(last_enum_expr, NULL);
201 			last_enum_expr = copy_list_range(defn, NULL);
202 			enum_counter = 1;
203 		} else {
204 			struct string_list *expr;
205 			char buf[20];
206 
207 			snprintf(buf, sizeof(buf), "%d", enum_counter++);
208 			if (last_enum_expr) {
209 				expr = copy_list_range(last_enum_expr, NULL);
210 				defn = concat_list(mk_node("("),
211 						   expr,
212 						   mk_node(")"),
213 						   mk_node("+"),
214 						   mk_node(buf), NULL);
215 			} else {
216 				defn = mk_node(buf);
217 			}
218 		}
219 	} else if (type == SYM_ENUM) {
220 		free_list(last_enum_expr, NULL);
221 		last_enum_expr = NULL;
222 		enum_counter = 0;
223 		if (!name)
224 			/* Anonymous enum definition, nothing more to do */
225 			return NULL;
226 	}
227 
228 	h = crc32(name);
229 	hash_for_each_possible(symbol_hashtable, sym, hnode, h) {
230 		if (map_to_ns(sym->type) != map_to_ns(type) ||
231 		    strcmp(name, sym->name))
232 			continue;
233 
234 		if (is_reference) {
235 			break;
236 		} else if (sym->type == type && 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 unchanged\n");
241 			}
242 			sym->is_declared = 1;
243 		} else if (sym->is_declared) {
244 			error_with_pos("redefinition of %s", name);
245 		} else 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 		} else {
252 			status = is_unknown_symbol(sym) ?
253 					STATUS_DEFINED : STATUS_MODIFIED;
254 			break;
255 		}
256 		free_list(defn, NULL);
257 		return sym;
258 	}
259 
260 	if (sym) {
261 		hash_del(&sym->hnode);
262 
263 		free_list(sym->defn, NULL);
264 		free(sym->name);
265 		free(sym);
266 		--nsyms;
267 	}
268 
269 	sym = xmalloc(sizeof(*sym));
270 	sym->name = xstrdup(name);
271 	sym->type = type;
272 	sym->defn = defn;
273 	sym->expansion_trail = NULL;
274 	sym->visited = NULL;
275 	sym->is_extern = is_extern;
276 
277 	hash_add(symbol_hashtable, &sym->hnode, h);
278 
279 	sym->is_declared = !is_reference;
280 	sym->status = status;
281 	sym->is_override = 0;
282 
283 	if (flag_debug) {
284 		if (symbol_types[type].name)
285 			fprintf(debugfile, "Defn for %s %s == <",
286 				symbol_types[type].name, name);
287 		else
288 			fprintf(debugfile, "Defn for type%d %s == <",
289 				type, name);
290 		if (is_extern)
291 			fputs("extern ", debugfile);
292 		print_list(debugfile, defn);
293 		fputs(">\n", debugfile);
294 	}
295 
296 	++nsyms;
297 	return sym;
298 }
299 
add_symbol(const char * name,enum symbol_type type,struct string_list * defn,int is_extern)300 struct symbol *add_symbol(const char *name, enum symbol_type type,
301 			  struct string_list *defn, int is_extern)
302 {
303 	return __add_symbol(name, type, defn, is_extern, 0);
304 }
305 
add_reference_symbol(const char * name,enum symbol_type type,struct string_list * defn,int is_extern)306 static struct symbol *add_reference_symbol(const char *name, enum symbol_type type,
307 				    struct string_list *defn, int is_extern)
308 {
309 	return __add_symbol(name, type, defn, is_extern, 1);
310 }
311 
312 /*----------------------------------------------------------------------*/
313 
free_node(struct string_list * node)314 void free_node(struct string_list *node)
315 {
316 	free(node->string);
317 	free(node);
318 }
319 
free_list(struct string_list * s,struct string_list * e)320 void free_list(struct string_list *s, struct string_list *e)
321 {
322 	while (s != e) {
323 		struct string_list *next = s->next;
324 		free_node(s);
325 		s = next;
326 	}
327 }
328 
mk_node(const char * string)329 static struct string_list *mk_node(const char *string)
330 {
331 	struct string_list *newnode;
332 
333 	newnode = xmalloc(sizeof(*newnode));
334 	newnode->string = xstrdup(string);
335 	newnode->tag = SYM_NORMAL;
336 	newnode->next = NULL;
337 
338 	return newnode;
339 }
340 
concat_list(struct string_list * start,...)341 static struct string_list *concat_list(struct string_list *start, ...)
342 {
343 	va_list ap;
344 	struct string_list *n, *n2;
345 
346 	if (!start)
347 		return NULL;
348 	for (va_start(ap, start); (n = va_arg(ap, struct string_list *));) {
349 		for (n2 = n; n2->next; n2 = n2->next)
350 			;
351 		n2->next = start;
352 		start = n;
353 	}
354 	va_end(ap);
355 	return start;
356 }
357 
copy_node(struct string_list * node)358 struct string_list *copy_node(struct string_list *node)
359 {
360 	struct string_list *newnode;
361 
362 	newnode = xmalloc(sizeof(*newnode));
363 	newnode->string = xstrdup(node->string);
364 	newnode->tag = node->tag;
365 
366 	return newnode;
367 }
368 
copy_list_range(struct string_list * start,struct string_list * end)369 struct string_list *copy_list_range(struct string_list *start,
370 				    struct string_list *end)
371 {
372 	struct string_list *res, *n;
373 
374 	if (start == end)
375 		return NULL;
376 	n = res = copy_node(start);
377 	for (start = start->next; start != end; start = start->next) {
378 		n->next = copy_node(start);
379 		n = n->next;
380 	}
381 	n->next = NULL;
382 	return res;
383 }
384 
equal_list(struct string_list * a,struct string_list * b)385 static int equal_list(struct string_list *a, struct string_list *b)
386 {
387 	while (a && b) {
388 		if (a->tag != b->tag || strcmp(a->string, b->string))
389 			return 0;
390 		a = a->next;
391 		b = b->next;
392 	}
393 
394 	return !a && !b;
395 }
396 
397 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
398 
read_node(FILE * f)399 static struct string_list *read_node(FILE *f)
400 {
401 	char buffer[256];
402 	struct string_list node = {
403 		.string = buffer,
404 		.tag = SYM_NORMAL };
405 	int c, in_string = 0;
406 
407 	while ((c = fgetc(f)) != EOF) {
408 		if (!in_string && c == ' ') {
409 			if (node.string == buffer)
410 				continue;
411 			break;
412 		} else if (c == '"') {
413 			in_string = !in_string;
414 		} else if (c == '\n') {
415 			if (node.string == buffer)
416 				return NULL;
417 			ungetc(c, f);
418 			break;
419 		}
420 		if (node.string >= buffer + sizeof(buffer) - 1) {
421 			fprintf(stderr, "Token too long\n");
422 			exit(1);
423 		}
424 		*node.string++ = c;
425 	}
426 	if (node.string == buffer)
427 		return NULL;
428 	*node.string = 0;
429 	node.string = buffer;
430 
431 	if (node.string[1] == '#') {
432 		size_t n;
433 
434 		for (n = 0; n < ARRAY_SIZE(symbol_types); n++) {
435 			if (node.string[0] == symbol_types[n].n) {
436 				node.tag = n;
437 				node.string += 2;
438 				return copy_node(&node);
439 			}
440 		}
441 		fprintf(stderr, "Unknown type %c\n", node.string[0]);
442 		exit(1);
443 	}
444 	return copy_node(&node);
445 }
446 
read_reference(FILE * f)447 static void read_reference(FILE *f)
448 {
449 	while (!feof(f)) {
450 		struct string_list *defn = NULL;
451 		struct string_list *sym, *def;
452 		int is_extern = 0, is_override = 0;
453 		struct symbol *subsym;
454 
455 		sym = read_node(f);
456 		if (sym && sym->tag == SYM_NORMAL &&
457 		    !strcmp(sym->string, "override")) {
458 			is_override = 1;
459 			free_node(sym);
460 			sym = read_node(f);
461 		}
462 		if (!sym)
463 			continue;
464 		def = read_node(f);
465 		if (def && def->tag == SYM_NORMAL &&
466 		    !strcmp(def->string, "extern")) {
467 			is_extern = 1;
468 			free_node(def);
469 			def = read_node(f);
470 		}
471 		while (def) {
472 			def->next = defn;
473 			defn = def;
474 			def = read_node(f);
475 		}
476 		subsym = add_reference_symbol(sym->string, sym->tag,
477 					      defn, is_extern);
478 		subsym->is_override = is_override;
479 		free_node(sym);
480 	}
481 }
482 
print_node(FILE * f,struct string_list * list)483 static void print_node(FILE * f, struct string_list *list)
484 {
485 	if (symbol_types[list->tag].n) {
486 		putc(symbol_types[list->tag].n, f);
487 		putc('#', f);
488 	}
489 	fputs(list->string, f);
490 }
491 
print_list(FILE * f,struct string_list * list)492 static void print_list(FILE * f, struct string_list *list)
493 {
494 	struct string_list **e, **b;
495 	struct string_list *tmp, **tmp2;
496 	int elem = 1;
497 
498 	if (list == NULL) {
499 		fputs("(nil)", f);
500 		return;
501 	}
502 
503 	tmp = list;
504 	while ((tmp = tmp->next) != NULL)
505 		elem++;
506 
507 	b = alloca(elem * sizeof(*e));
508 	e = b + elem;
509 	tmp2 = e - 1;
510 
511 	(*tmp2--) = list;
512 	while ((list = list->next) != NULL)
513 		*(tmp2--) = list;
514 
515 	while (b != e) {
516 		print_node(f, *b++);
517 		putc(' ', f);
518 	}
519 }
520 
expand_and_crc_sym(struct symbol * sym,uint32_t crc)521 static uint32_t expand_and_crc_sym(struct symbol *sym, uint32_t crc)
522 {
523 	struct string_list *list = sym->defn;
524 	struct string_list **e, **b;
525 	struct string_list *tmp, **tmp2;
526 	int elem = 1;
527 
528 	if (!list)
529 		return crc;
530 
531 	tmp = list;
532 	while ((tmp = tmp->next) != NULL)
533 		elem++;
534 
535 	b = alloca(elem * sizeof(*e));
536 	e = b + elem;
537 	tmp2 = e - 1;
538 
539 	*(tmp2--) = list;
540 	while ((list = list->next) != NULL)
541 		*(tmp2--) = list;
542 
543 	while (b != e) {
544 		struct string_list *cur;
545 		struct symbol *subsym;
546 
547 		cur = *(b++);
548 		switch (cur->tag) {
549 		case SYM_NORMAL:
550 			if (flag_dump_defs)
551 				fprintf(debugfile, "%s ", cur->string);
552 			crc = partial_crc32(cur->string, crc);
553 			crc = partial_crc32_one(' ', crc);
554 			break;
555 
556 		case SYM_ENUM_CONST:
557 		case SYM_TYPEDEF:
558 			subsym = find_symbol(cur->string, cur->tag, 0);
559 			/* FIXME: Bad reference files can segfault here. */
560 			if (subsym->expansion_trail) {
561 				if (flag_dump_defs)
562 					fprintf(debugfile, "%s ", cur->string);
563 				crc = partial_crc32(cur->string, crc);
564 				crc = partial_crc32_one(' ', crc);
565 			} else {
566 				subsym->expansion_trail = expansion_trail;
567 				expansion_trail = subsym;
568 				crc = expand_and_crc_sym(subsym, crc);
569 			}
570 			break;
571 
572 		case SYM_STRUCT:
573 		case SYM_UNION:
574 		case SYM_ENUM:
575 			subsym = find_symbol(cur->string, cur->tag, 0);
576 			if (!subsym) {
577 				struct string_list *n;
578 
579 				error_with_pos("expand undefined %s %s",
580 					       symbol_types[cur->tag].name,
581 					       cur->string);
582 				n = concat_list(mk_node
583 						(symbol_types[cur->tag].name),
584 						mk_node(cur->string),
585 						mk_node("{"),
586 						mk_node("UNKNOWN"),
587 						mk_node("}"), NULL);
588 				subsym =
589 				    add_symbol(cur->string, cur->tag, n, 0);
590 			}
591 			if (subsym->expansion_trail) {
592 				if (flag_dump_defs) {
593 					fprintf(debugfile, "%s %s ",
594 						symbol_types[cur->tag].name,
595 						cur->string);
596 				}
597 
598 				crc = partial_crc32(symbol_types[cur->tag].name,
599 						    crc);
600 				crc = partial_crc32_one(' ', crc);
601 				crc = partial_crc32(cur->string, crc);
602 				crc = partial_crc32_one(' ', crc);
603 			} else {
604 				subsym->expansion_trail = expansion_trail;
605 				expansion_trail = subsym;
606 				crc = expand_and_crc_sym(subsym, crc);
607 			}
608 			break;
609 		}
610 	}
611 
612 	{
613 		static struct symbol **end = &visited_symbols;
614 
615 		if (!sym->visited) {
616 			*end = sym;
617 			end = &sym->visited;
618 			sym->visited = (struct symbol *)-1L;
619 		}
620 	}
621 
622 	return crc;
623 }
624 
export_symbol(const char * name)625 void export_symbol(const char *name)
626 {
627 	struct symbol *sym;
628 	uint32_t crc;
629 	int has_changed = 0;
630 
631 	sym = find_symbol(name, SYM_NORMAL, 0);
632 	if (!sym) {
633 		error_with_pos("export undefined symbol %s", name);
634 		return;
635 	}
636 
637 	if (flag_dump_defs)
638 		fprintf(debugfile, "Export %s == <", name);
639 
640 	expansion_trail = (struct symbol *)-1L;
641 
642 	sym->expansion_trail = expansion_trail;
643 	expansion_trail = sym;
644 	crc = expand_and_crc_sym(sym, 0xffffffff) ^ 0xffffffff;
645 
646 	sym = expansion_trail;
647 	while (sym != (struct symbol *)-1L) {
648 		struct symbol *n = sym->expansion_trail;
649 
650 		if (sym->status != STATUS_UNCHANGED) {
651 			if (!has_changed) {
652 				print_location();
653 				fprintf(stderr,
654 					"%s: %s: modversion changed because of changes in ",
655 					flag_preserve ? "error" : "warning",
656 					name);
657 			} else {
658 				fprintf(stderr, ", ");
659 			}
660 			print_type_name(sym->type, sym->name);
661 			if (sym->status == STATUS_DEFINED)
662 				fprintf(stderr, " (became defined)");
663 			has_changed = 1;
664 			if (flag_preserve)
665 				errors++;
666 		}
667 		sym->expansion_trail = 0;
668 		sym = n;
669 	}
670 	if (has_changed)
671 		fprintf(stderr, "\n");
672 
673 	if (flag_dump_defs)
674 		fputs(">\n", debugfile);
675 
676 	printf("#SYMVER %s 0x%08lx\n", name, (unsigned long)crc);
677 }
678 
679 /*----------------------------------------------------------------------*/
680 
print_location(void)681 static void print_location(void)
682 {
683 	fprintf(stderr, "%s:%d: ", cur_filename ? : "<stdin>", cur_line);
684 }
685 
print_type_name(enum symbol_type type,const char * name)686 static void print_type_name(enum symbol_type type, const char *name)
687 {
688 	if (symbol_types[type].name)
689 		fprintf(stderr, "%s %s", symbol_types[type].name, name);
690 	else
691 		fprintf(stderr, "%s", name);
692 }
693 
error_with_pos(const char * fmt,...)694 void error_with_pos(const char *fmt, ...)
695 {
696 	va_list args;
697 
698 	if (flag_warnings) {
699 		print_location();
700 
701 		va_start(args, fmt);
702 		vfprintf(stderr, fmt, args);
703 		va_end(args);
704 		putc('\n', stderr);
705 
706 		errors++;
707 	}
708 }
709 
genksyms_usage(void)710 static void genksyms_usage(void)
711 {
712 	fputs("Usage:\n" "genksyms [-adDTwqhVR] > /path/to/.tmp_obj.ver\n" "\n"
713 	      "  -d, --debug           Increment the debug level (repeatable)\n"
714 	      "  -D, --dump            Dump expanded symbol defs (for debugging only)\n"
715 	      "  -r, --reference file  Read reference symbols from a file\n"
716 	      "  -T, --dump-types file Dump expanded types into file\n"
717 	      "  -p, --preserve        Preserve reference modversions or fail\n"
718 	      "  -w, --warnings        Enable warnings\n"
719 	      "  -q, --quiet           Disable warnings (default)\n"
720 	      "  -h, --help            Print this message\n"
721 	      "  -V, --version         Print the release version\n"
722 	      , stderr);
723 }
724 
main(int argc,char ** argv)725 int main(int argc, char **argv)
726 {
727 	FILE *dumpfile = NULL, *ref_file = NULL;
728 	int o;
729 
730 	struct option long_opts[] = {
731 		{"debug", 0, 0, 'd'},
732 		{"warnings", 0, 0, 'w'},
733 		{"quiet", 0, 0, 'q'},
734 		{"dump", 0, 0, 'D'},
735 		{"reference", 1, 0, 'r'},
736 		{"dump-types", 1, 0, 'T'},
737 		{"preserve", 0, 0, 'p'},
738 		{"version", 0, 0, 'V'},
739 		{"help", 0, 0, 'h'},
740 		{0, 0, 0, 0}
741 	};
742 
743 	while ((o = getopt_long(argc, argv, "dwqVDr:T:ph",
744 				&long_opts[0], NULL)) != EOF)
745 		switch (o) {
746 		case 'd':
747 			flag_debug++;
748 			break;
749 		case 'w':
750 			flag_warnings = 1;
751 			break;
752 		case 'q':
753 			flag_warnings = 0;
754 			break;
755 		case 'V':
756 			fputs("genksyms version 2.5.60\n", stderr);
757 			break;
758 		case 'D':
759 			flag_dump_defs = 1;
760 			break;
761 		case 'r':
762 			flag_reference = 1;
763 			ref_file = fopen(optarg, "r");
764 			if (!ref_file) {
765 				perror(optarg);
766 				return 1;
767 			}
768 			break;
769 		case 'T':
770 			flag_dump_types = 1;
771 			dumpfile = fopen(optarg, "w");
772 			if (!dumpfile) {
773 				perror(optarg);
774 				return 1;
775 			}
776 			break;
777 		case 'p':
778 			flag_preserve = 1;
779 			break;
780 		case 'h':
781 			genksyms_usage();
782 			return 0;
783 		default:
784 			genksyms_usage();
785 			return 1;
786 		}
787 	{
788 		extern int yydebug;
789 		extern int yy_flex_debug;
790 
791 		yydebug = (flag_debug > 1);
792 		yy_flex_debug = (flag_debug > 2);
793 
794 		debugfile = stderr;
795 		/* setlinebuf(debugfile); */
796 	}
797 
798 	if (flag_reference) {
799 		read_reference(ref_file);
800 		fclose(ref_file);
801 	}
802 
803 	yyparse();
804 
805 	if (flag_dump_types && visited_symbols) {
806 		while (visited_symbols != (struct symbol *)-1L) {
807 			struct symbol *sym = visited_symbols;
808 
809 			if (sym->is_override)
810 				fputs("override ", dumpfile);
811 			if (symbol_types[sym->type].n) {
812 				putc(symbol_types[sym->type].n, dumpfile);
813 				putc('#', dumpfile);
814 			}
815 			fputs(sym->name, dumpfile);
816 			putc(' ', dumpfile);
817 			if (sym->is_extern)
818 				fputs("extern ", dumpfile);
819 			print_list(dumpfile, sym->defn);
820 			putc('\n', dumpfile);
821 
822 			visited_symbols = sym->visited;
823 			sym->visited = NULL;
824 		}
825 	}
826 
827 	if (flag_debug) {
828 		fprintf(debugfile, "Hash table occupancy %d/%zd = %g\n",
829 			nsyms, HASH_SIZE(symbol_hashtable),
830 			(double)nsyms / HASH_SIZE(symbol_hashtable));
831 	}
832 
833 	if (dumpfile)
834 		fclose(dumpfile);
835 
836 	return errors != 0;
837 }
838