Linux Audio

Check our new training course

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