File Index
Files and directories
Sign in
FILE

genksyms.c

File preview with syntax highlighting.

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