Linux Audio

Check our new training course

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