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