Linux Audio

Check our new training course

Linux debugging, profiling, tracing and performance analysis training

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