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