Linux Audio

Check our new training course

Loading...
v4.6
 
  1/* Generate kernel symbol version hashes.
  2   Copyright 1996, 1997 Linux International.
  3
  4   New implementation contributed by Richard Henderson <rth@tamu.edu>
  5   Based on original work by Bjorn Ekwall <bj0rn@blox.se>
  6
  7   This file was part of the Linux modutils 2.4.22: moved back into the
  8   kernel sources by Rusty Russell/Kai Germaschewski.
  9
 10   This program is free software; you can redistribute it and/or modify it
 11   under the terms of the GNU General Public License as published by the
 12   Free Software Foundation; either version 2 of the License, or (at your
 13   option) any later version.
 14
 15   This program is distributed in the hope that it will be useful, but
 16   WITHOUT ANY WARRANTY; without even the implied warranty of
 17   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 18   General Public License for more details.
 19
 20   You should have received a copy of the GNU General Public License
 21   along with this program; if not, write to the Free Software Foundation,
 22   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 23
 24#include <stdio.h>
 25#include <string.h>
 26#include <stdlib.h>
 27#include <unistd.h>
 28#include <assert.h>
 29#include <stdarg.h>
 30#ifdef __GNU_LIBRARY__
 31#include <getopt.h>
 32#endif				/* __GNU_LIBRARY__ */
 33
 34#include "genksyms.h"
 35/*----------------------------------------------------------------------*/
 36
 37#define HASH_BUCKETS  4096
 38
 39static struct symbol *symtab[HASH_BUCKETS];
 40static FILE *debugfile;
 41
 42int cur_line = 1;
 43char *cur_filename, *source_file;
 44int in_source_file;
 45
 46static int flag_debug, flag_dump_defs, flag_reference, flag_dump_types,
 47	   flag_preserve, flag_warnings;
 48static const char *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("%s__crc_%s = 0x%08lx ;\n", mod_prefix, name, crc);
697	}
698}
699
700/*----------------------------------------------------------------------*/
701
702static void print_location(void)
703{
704	fprintf(stderr, "%s:%d: ", cur_filename ? : "<stdin>", cur_line);
705}
706
707static void print_type_name(enum symbol_type type, const char *name)
708{
709	if (symbol_types[type].name)
710		fprintf(stderr, "%s %s", symbol_types[type].name, name);
711	else
712		fprintf(stderr, "%s", name);
713}
714
715void error_with_pos(const char *fmt, ...)
716{
717	va_list args;
718
719	if (flag_warnings) {
720		print_location();
721
722		va_start(args, fmt);
723		vfprintf(stderr, fmt, args);
724		va_end(args);
725		putc('\n', stderr);
726
727		errors++;
728	}
729}
730
731static void genksyms_usage(void)
732{
733	fputs("Usage:\n" "genksyms [-adDTwqhV] > /path/to/.tmp_obj.ver\n" "\n"
734#ifdef __GNU_LIBRARY__
735	      "  -s, --symbol-prefix   Select symbol prefix\n"
736	      "  -d, --debug           Increment the debug level (repeatable)\n"
737	      "  -D, --dump            Dump expanded symbol defs (for debugging only)\n"
738	      "  -r, --reference file  Read reference symbols from a file\n"
739	      "  -T, --dump-types file Dump expanded types into file\n"
740	      "  -p, --preserve        Preserve reference modversions or fail\n"
741	      "  -w, --warnings        Enable warnings\n"
742	      "  -q, --quiet           Disable warnings (default)\n"
743	      "  -h, --help            Print this message\n"
744	      "  -V, --version         Print the release version\n"
745#else				/* __GNU_LIBRARY__ */
746	      "  -s                    Select symbol prefix\n"
747	      "  -d                    Increment the debug level (repeatable)\n"
748	      "  -D                    Dump expanded symbol defs (for debugging only)\n"
749	      "  -r file               Read reference symbols from a file\n"
750	      "  -T file               Dump expanded types into file\n"
751	      "  -p                    Preserve reference modversions or fail\n"
752	      "  -w                    Enable warnings\n"
753	      "  -q                    Disable warnings (default)\n"
754	      "  -h                    Print this message\n"
755	      "  -V                    Print the release version\n"
756#endif				/* __GNU_LIBRARY__ */
757	      , stderr);
758}
759
760int main(int argc, char **argv)
761{
762	FILE *dumpfile = NULL, *ref_file = NULL;
763	int o;
764
765#ifdef __GNU_LIBRARY__
766	struct option long_opts[] = {
767		{"symbol-prefix", 1, 0, 's'},
768		{"debug", 0, 0, 'd'},
769		{"warnings", 0, 0, 'w'},
770		{"quiet", 0, 0, 'q'},
771		{"dump", 0, 0, 'D'},
772		{"reference", 1, 0, 'r'},
773		{"dump-types", 1, 0, 'T'},
774		{"preserve", 0, 0, 'p'},
775		{"version", 0, 0, 'V'},
776		{"help", 0, 0, 'h'},
777		{0, 0, 0, 0}
778	};
779
780	while ((o = getopt_long(argc, argv, "s:dwqVDr:T:ph",
781				&long_opts[0], NULL)) != EOF)
782#else				/* __GNU_LIBRARY__ */
783	while ((o = getopt(argc, argv, "s:dwqVDr:T:ph")) != EOF)
784#endif				/* __GNU_LIBRARY__ */
785		switch (o) {
786		case 's':
787			mod_prefix = optarg;
788			break;
789		case 'd':
790			flag_debug++;
791			break;
792		case 'w':
793			flag_warnings = 1;
794			break;
795		case 'q':
796			flag_warnings = 0;
797			break;
798		case 'V':
799			fputs("genksyms version 2.5.60\n", stderr);
800			break;
801		case 'D':
802			flag_dump_defs = 1;
803			break;
804		case 'r':
805			flag_reference = 1;
806			ref_file = fopen(optarg, "r");
807			if (!ref_file) {
808				perror(optarg);
809				return 1;
810			}
811			break;
812		case 'T':
813			flag_dump_types = 1;
814			dumpfile = fopen(optarg, "w");
815			if (!dumpfile) {
816				perror(optarg);
817				return 1;
818			}
819			break;
820		case 'p':
821			flag_preserve = 1;
822			break;
823		case 'h':
824			genksyms_usage();
825			return 0;
826		default:
827			genksyms_usage();
828			return 1;
829		}
830	{
831		extern int yydebug;
832		extern int yy_flex_debug;
833
834		yydebug = (flag_debug > 1);
835		yy_flex_debug = (flag_debug > 2);
836
837		debugfile = stderr;
838		/* setlinebuf(debugfile); */
839	}
840
841	if (flag_reference) {
842		read_reference(ref_file);
843		fclose(ref_file);
844	}
845
846	yyparse();
847
848	if (flag_dump_types && visited_symbols) {
849		while (visited_symbols != (struct symbol *)-1L) {
850			struct symbol *sym = visited_symbols;
851
852			if (sym->is_override)
853				fputs("override ", dumpfile);
854			if (symbol_types[sym->type].n) {
855				putc(symbol_types[sym->type].n, dumpfile);
856				putc('#', dumpfile);
857			}
858			fputs(sym->name, dumpfile);
859			putc(' ', dumpfile);
860			if (sym->is_extern)
861				fputs("extern ", dumpfile);
862			print_list(dumpfile, sym->defn);
863			putc('\n', dumpfile);
864
865			visited_symbols = sym->visited;
866			sym->visited = NULL;
867		}
868	}
869
870	if (flag_debug) {
871		fprintf(debugfile, "Hash table occupancy %d/%d = %g\n",
872			nsyms, HASH_BUCKETS,
873			(double)nsyms / (double)HASH_BUCKETS);
874	}
 
 
 
875
876	return errors != 0;
877}
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}