genksyms.c 22.5 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
/* Generate kernel symbol version hashes.
   Copyright 1996, 1997 Linux International.

   New implementation contributed by Richard Henderson <rth@tamu.edu>
   Based on original work by Bjorn Ekwall <bj0rn@blox.se>

   This file was part of the Linux modutils 2.4.22: moved back into the
   kernel sources by Rusty Russell/Kai Germaschewski.

   This program is free software; you can redistribute it and/or modify it
   under the terms of the GNU General Public License as published by the
   Free Software Foundation; either version 2 of the License, or (at your
   option) any later version.

   This program is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software Foundation,
   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <stdarg.h>
#ifdef __GNU_LIBRARY__
#include <getopt.h>
S
Sam Ravnborg 已提交
32
#endif				/* __GNU_LIBRARY__ */
L
Linus Torvalds 已提交
33 34 35 36 37 38 39

#include "genksyms.h"
/*----------------------------------------------------------------------*/

#define HASH_BUCKETS  4096

static struct symbol *symtab[HASH_BUCKETS];
S
Sam Ravnborg 已提交
40
static FILE *debugfile;
L
Linus Torvalds 已提交
41 42

int cur_line = 1;
43 44
char *cur_filename, *source_file;
int in_source_file;
L
Linus Torvalds 已提交
45

46
static int flag_debug, flag_dump_defs, flag_reference, flag_dump_types,
47
	   flag_preserve, flag_warnings;
S
Sam Ravnborg 已提交
48
static const char *mod_prefix = "";
L
Linus Torvalds 已提交
49 50 51 52 53

static int errors;
static int nsyms;

static struct symbol *expansion_trail;
54
static struct symbol *visited_symbols;
L
Linus Torvalds 已提交
55

56 57 58 59 60 61 62 63 64
static const struct {
	int n;
	const char *name;
} symbol_types[] = {
	[SYM_NORMAL]     = { 0, NULL},
	[SYM_TYPEDEF]    = {'t', "typedef"},
	[SYM_ENUM]       = {'e', "enum"},
	[SYM_STRUCT]     = {'s', "struct"},
	[SYM_UNION]      = {'u', "union"},
65
	[SYM_ENUM_CONST] = {'E', "enum constant"},
L
Linus Torvalds 已提交
66 67
};

S
Sam Ravnborg 已提交
68 69
static int equal_list(struct string_list *a, struct string_list *b);
static void print_list(FILE * f, struct string_list *list);
70 71
static struct string_list *concat_list(struct string_list *start, ...);
static struct string_list *mk_node(const char *string);
72 73
static void print_location(void);
static void print_type_name(enum symbol_type type, const char *name);
S
Sam Ravnborg 已提交
74

L
Linus Torvalds 已提交
75 76
/*----------------------------------------------------------------------*/

S
Sam Ravnborg 已提交
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
static const unsigned int crctab32[] = {
	0x00000000U, 0x77073096U, 0xee0e612cU, 0x990951baU, 0x076dc419U,
	0x706af48fU, 0xe963a535U, 0x9e6495a3U, 0x0edb8832U, 0x79dcb8a4U,
	0xe0d5e91eU, 0x97d2d988U, 0x09b64c2bU, 0x7eb17cbdU, 0xe7b82d07U,
	0x90bf1d91U, 0x1db71064U, 0x6ab020f2U, 0xf3b97148U, 0x84be41deU,
	0x1adad47dU, 0x6ddde4ebU, 0xf4d4b551U, 0x83d385c7U, 0x136c9856U,
	0x646ba8c0U, 0xfd62f97aU, 0x8a65c9ecU, 0x14015c4fU, 0x63066cd9U,
	0xfa0f3d63U, 0x8d080df5U, 0x3b6e20c8U, 0x4c69105eU, 0xd56041e4U,
	0xa2677172U, 0x3c03e4d1U, 0x4b04d447U, 0xd20d85fdU, 0xa50ab56bU,
	0x35b5a8faU, 0x42b2986cU, 0xdbbbc9d6U, 0xacbcf940U, 0x32d86ce3U,
	0x45df5c75U, 0xdcd60dcfU, 0xabd13d59U, 0x26d930acU, 0x51de003aU,
	0xc8d75180U, 0xbfd06116U, 0x21b4f4b5U, 0x56b3c423U, 0xcfba9599U,
	0xb8bda50fU, 0x2802b89eU, 0x5f058808U, 0xc60cd9b2U, 0xb10be924U,
	0x2f6f7c87U, 0x58684c11U, 0xc1611dabU, 0xb6662d3dU, 0x76dc4190U,
	0x01db7106U, 0x98d220bcU, 0xefd5102aU, 0x71b18589U, 0x06b6b51fU,
	0x9fbfe4a5U, 0xe8b8d433U, 0x7807c9a2U, 0x0f00f934U, 0x9609a88eU,
	0xe10e9818U, 0x7f6a0dbbU, 0x086d3d2dU, 0x91646c97U, 0xe6635c01U,
	0x6b6b51f4U, 0x1c6c6162U, 0x856530d8U, 0xf262004eU, 0x6c0695edU,
	0x1b01a57bU, 0x8208f4c1U, 0xf50fc457U, 0x65b0d9c6U, 0x12b7e950U,
	0x8bbeb8eaU, 0xfcb9887cU, 0x62dd1ddfU, 0x15da2d49U, 0x8cd37cf3U,
	0xfbd44c65U, 0x4db26158U, 0x3ab551ceU, 0xa3bc0074U, 0xd4bb30e2U,
	0x4adfa541U, 0x3dd895d7U, 0xa4d1c46dU, 0xd3d6f4fbU, 0x4369e96aU,
	0x346ed9fcU, 0xad678846U, 0xda60b8d0U, 0x44042d73U, 0x33031de5U,
	0xaa0a4c5fU, 0xdd0d7cc9U, 0x5005713cU, 0x270241aaU, 0xbe0b1010U,
	0xc90c2086U, 0x5768b525U, 0x206f85b3U, 0xb966d409U, 0xce61e49fU,
	0x5edef90eU, 0x29d9c998U, 0xb0d09822U, 0xc7d7a8b4U, 0x59b33d17U,
	0x2eb40d81U, 0xb7bd5c3bU, 0xc0ba6cadU, 0xedb88320U, 0x9abfb3b6U,
	0x03b6e20cU, 0x74b1d29aU, 0xead54739U, 0x9dd277afU, 0x04db2615U,
	0x73dc1683U, 0xe3630b12U, 0x94643b84U, 0x0d6d6a3eU, 0x7a6a5aa8U,
	0xe40ecf0bU, 0x9309ff9dU, 0x0a00ae27U, 0x7d079eb1U, 0xf00f9344U,
	0x8708a3d2U, 0x1e01f268U, 0x6906c2feU, 0xf762575dU, 0x806567cbU,
	0x196c3671U, 0x6e6b06e7U, 0xfed41b76U, 0x89d32be0U, 0x10da7a5aU,
	0x67dd4accU, 0xf9b9df6fU, 0x8ebeeff9U, 0x17b7be43U, 0x60b08ed5U,
	0xd6d6a3e8U, 0xa1d1937eU, 0x38d8c2c4U, 0x4fdff252U, 0xd1bb67f1U,
	0xa6bc5767U, 0x3fb506ddU, 0x48b2364bU, 0xd80d2bdaU, 0xaf0a1b4cU,
	0x36034af6U, 0x41047a60U, 0xdf60efc3U, 0xa867df55U, 0x316e8eefU,
	0x4669be79U, 0xcb61b38cU, 0xbc66831aU, 0x256fd2a0U, 0x5268e236U,
	0xcc0c7795U, 0xbb0b4703U, 0x220216b9U, 0x5505262fU, 0xc5ba3bbeU,
	0xb2bd0b28U, 0x2bb45a92U, 0x5cb36a04U, 0xc2d7ffa7U, 0xb5d0cf31U,
	0x2cd99e8bU, 0x5bdeae1dU, 0x9b64c2b0U, 0xec63f226U, 0x756aa39cU,
	0x026d930aU, 0x9c0906a9U, 0xeb0e363fU, 0x72076785U, 0x05005713U,
	0x95bf4a82U, 0xe2b87a14U, 0x7bb12baeU, 0x0cb61b38U, 0x92d28e9bU,
	0xe5d5be0dU, 0x7cdcefb7U, 0x0bdbdf21U, 0x86d3d2d4U, 0xf1d4e242U,
	0x68ddb3f8U, 0x1fda836eU, 0x81be16cdU, 0xf6b9265bU, 0x6fb077e1U,
	0x18b74777U, 0x88085ae6U, 0xff0f6a70U, 0x66063bcaU, 0x11010b5cU,
	0x8f659effU, 0xf862ae69U, 0x616bffd3U, 0x166ccf45U, 0xa00ae278U,
	0xd70dd2eeU, 0x4e048354U, 0x3903b3c2U, 0xa7672661U, 0xd06016f7U,
	0x4969474dU, 0x3e6e77dbU, 0xaed16a4aU, 0xd9d65adcU, 0x40df0b66U,
	0x37d83bf0U, 0xa9bcae53U, 0xdebb9ec5U, 0x47b2cf7fU, 0x30b5ffe9U,
	0xbdbdf21cU, 0xcabac28aU, 0x53b39330U, 0x24b4a3a6U, 0xbad03605U,
	0xcdd70693U, 0x54de5729U, 0x23d967bfU, 0xb3667a2eU, 0xc4614ab8U,
	0x5d681b02U, 0x2a6f2b94U, 0xb40bbe37U, 0xc30c8ea1U, 0x5a05df1bU,
	0x2d02ef8dU
L
Linus Torvalds 已提交
130 131
};

S
Sam Ravnborg 已提交
132
static unsigned long partial_crc32_one(unsigned char c, unsigned long crc)
L
Linus Torvalds 已提交
133
{
S
Sam Ravnborg 已提交
134
	return crctab32[(crc ^ c) & 0xff] ^ (crc >> 8);
L
Linus Torvalds 已提交
135 136
}

S
Sam Ravnborg 已提交
137
static unsigned long partial_crc32(const char *s, unsigned long crc)
L
Linus Torvalds 已提交
138
{
S
Sam Ravnborg 已提交
139 140 141
	while (*s)
		crc = partial_crc32_one(*s++, crc);
	return crc;
L
Linus Torvalds 已提交
142 143
}

S
Sam Ravnborg 已提交
144
static unsigned long crc32(const char *s)
L
Linus Torvalds 已提交
145
{
S
Sam Ravnborg 已提交
146
	return partial_crc32(s, 0xffffffff) ^ 0xffffffff;
L
Linus Torvalds 已提交
147 148 149 150
}

/*----------------------------------------------------------------------*/

S
Sam Ravnborg 已提交
151
static enum symbol_type map_to_ns(enum symbol_type t)
L
Linus Torvalds 已提交
152
{
153 154 155 156 157 158 159 160 161 162
	switch (t) {
	case SYM_ENUM_CONST:
	case SYM_NORMAL:
	case SYM_TYPEDEF:
		return SYM_NORMAL;
	case SYM_ENUM:
	case SYM_STRUCT:
	case SYM_UNION:
		return SYM_STRUCT;
	}
S
Sam Ravnborg 已提交
163
	return t;
L
Linus Torvalds 已提交
164 165
}

166
struct symbol *find_symbol(const char *name, enum symbol_type ns, int exact)
L
Linus Torvalds 已提交
167
{
S
Sam Ravnborg 已提交
168 169
	unsigned long h = crc32(name) % HASH_BUCKETS;
	struct symbol *sym;
L
Linus Torvalds 已提交
170

S
Sam Ravnborg 已提交
171
	for (sym = symtab[h]; sym; sym = sym->hash_next)
S
Sam Ravnborg 已提交
172
		if (map_to_ns(sym->type) == map_to_ns(ns) &&
173 174
		    strcmp(name, sym->name) == 0 &&
		    sym->is_declared)
S
Sam Ravnborg 已提交
175
			break;
L
Linus Torvalds 已提交
176

177 178
	if (exact && sym && sym->type != ns)
		return NULL;
S
Sam Ravnborg 已提交
179
	return sym;
L
Linus Torvalds 已提交
180 181
}

182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
static int is_unknown_symbol(struct symbol *sym)
{
	struct string_list *defn;

	return ((sym->type == SYM_STRUCT ||
		 sym->type == SYM_UNION ||
		 sym->type == SYM_ENUM) &&
		(defn = sym->defn)  && defn->tag == SYM_NORMAL &&
			strcmp(defn->string, "}") == 0 &&
		(defn = defn->next) && defn->tag == SYM_NORMAL &&
			strcmp(defn->string, "UNKNOWN") == 0 &&
		(defn = defn->next) && defn->tag == SYM_NORMAL &&
			strcmp(defn->string, "{") == 0);
}

197
static struct symbol *__add_symbol(const char *name, enum symbol_type type,
198 199
			    struct string_list *defn, int is_extern,
			    int is_reference)
L
Linus Torvalds 已提交
200
{
201
	unsigned long h;
S
Sam Ravnborg 已提交
202
	struct symbol *sym;
203
	enum symbol_status status = STATUS_UNCHANGED;
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239
	/* The parser adds symbols in the order their declaration completes,
	 * so it is safe to store the value of the previous enum constant in
	 * a static variable.
	 */
	static int enum_counter;
	static struct string_list *last_enum_expr;

	if (type == SYM_ENUM_CONST) {
		if (defn) {
			free_list(last_enum_expr, NULL);
			last_enum_expr = copy_list_range(defn, NULL);
			enum_counter = 1;
		} else {
			struct string_list *expr;
			char buf[20];

			snprintf(buf, sizeof(buf), "%d", enum_counter++);
			if (last_enum_expr) {
				expr = copy_list_range(last_enum_expr, NULL);
				defn = concat_list(mk_node("("),
						   expr,
						   mk_node(")"),
						   mk_node("+"),
						   mk_node(buf), NULL);
			} else {
				defn = mk_node(buf);
			}
		}
	} else if (type == SYM_ENUM) {
		free_list(last_enum_expr, NULL);
		last_enum_expr = NULL;
		enum_counter = 0;
		if (!name)
			/* Anonymous enum definition, nothing more to do */
			return NULL;
	}
S
Sam Ravnborg 已提交
240

241
	h = crc32(name) % HASH_BUCKETS;
S
Sam Ravnborg 已提交
242
	for (sym = symtab[h]; sym; sym = sym->hash_next) {
243 244 245 246 247 248
		if (map_to_ns(sym->type) == map_to_ns(type) &&
		    strcmp(name, sym->name) == 0) {
			if (is_reference)
				/* fall through */ ;
			else if (sym->type == type &&
				 equal_list(sym->defn, defn)) {
249 250 251 252 253 254
				if (!sym->is_declared && sym->is_override) {
					print_location();
					print_type_name(type, name);
					fprintf(stderr, " modversion is "
						"unchanged\n");
				}
255 256 257
				sym->is_declared = 1;
				return sym;
			} else if (!sym->is_declared) {
258 259 260 261 262 263 264 265 266 267 268
				if (sym->is_override && flag_preserve) {
					print_location();
					fprintf(stderr, "ignoring ");
					print_type_name(type, name);
					fprintf(stderr, " modversion change\n");
					sym->is_declared = 1;
					return sym;
				} else {
					status = is_unknown_symbol(sym) ?
						STATUS_DEFINED : STATUS_MODIFIED;
				}
269
			} else {
S
Sam Ravnborg 已提交
270
				error_with_pos("redefinition of %s", name);
271 272 273
				return sym;
			}
			break;
S
Sam Ravnborg 已提交
274
		}
S
Sam Ravnborg 已提交
275
	}
S
Sam Ravnborg 已提交
276

277 278 279 280 281 282 283 284 285 286 287 288
	if (sym) {
		struct symbol **psym;

		for (psym = &symtab[h]; *psym; psym = &(*psym)->hash_next) {
			if (*psym == sym) {
				*psym = sym->hash_next;
				break;
			}
		}
		--nsyms;
	}

S
Sam Ravnborg 已提交
289 290 291 292 293
	sym = xmalloc(sizeof(*sym));
	sym->name = name;
	sym->type = type;
	sym->defn = defn;
	sym->expansion_trail = NULL;
294
	sym->visited = NULL;
S
Sam Ravnborg 已提交
295 296 297 298 299
	sym->is_extern = is_extern;

	sym->hash_next = symtab[h];
	symtab[h] = sym;

300 301
	sym->is_declared = !is_reference;
	sym->status = status;
302
	sym->is_override = 0;
303

S
Sam Ravnborg 已提交
304
	if (flag_debug) {
305 306 307 308 309 310
		if (symbol_types[type].name)
			fprintf(debugfile, "Defn for %s %s == <",
				symbol_types[type].name, name);
		else
			fprintf(debugfile, "Defn for type%d %s == <",
				type, name);
S
Sam Ravnborg 已提交
311 312 313 314 315 316 317
		if (is_extern)
			fputs("extern ", debugfile);
		print_list(debugfile, defn);
		fputs(">\n", debugfile);
	}

	++nsyms;
L
Linus Torvalds 已提交
318 319 320
	return sym;
}

321 322 323 324 325 326
struct symbol *add_symbol(const char *name, enum symbol_type type,
			  struct string_list *defn, int is_extern)
{
	return __add_symbol(name, type, defn, is_extern, 0);
}

327
static struct symbol *add_reference_symbol(const char *name, enum symbol_type type,
328 329 330 331 332
				    struct string_list *defn, int is_extern)
{
	return __add_symbol(name, type, defn, is_extern, 1);
}

L
Linus Torvalds 已提交
333 334
/*----------------------------------------------------------------------*/

S
Sam Ravnborg 已提交
335
void free_node(struct string_list *node)
L
Linus Torvalds 已提交
336
{
S
Sam Ravnborg 已提交
337 338
	free(node->string);
	free(node);
L
Linus Torvalds 已提交
339 340
}

S
Sam Ravnborg 已提交
341
void free_list(struct string_list *s, struct string_list *e)
L
Linus Torvalds 已提交
342
{
S
Sam Ravnborg 已提交
343 344 345 346 347
	while (s != e) {
		struct string_list *next = s->next;
		free_node(s);
		s = next;
	}
L
Linus Torvalds 已提交
348 349
}

350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378
static struct string_list *mk_node(const char *string)
{
	struct string_list *newnode;

	newnode = xmalloc(sizeof(*newnode));
	newnode->string = xstrdup(string);
	newnode->tag = SYM_NORMAL;
	newnode->next = NULL;

	return newnode;
}

static struct string_list *concat_list(struct string_list *start, ...)
{
	va_list ap;
	struct string_list *n, *n2;

	if (!start)
		return NULL;
	for (va_start(ap, start); (n = va_arg(ap, struct string_list *));) {
		for (n2 = n; n2->next; n2 = n2->next)
			;
		n2->next = start;
		start = n;
	}
	va_end(ap);
	return start;
}

S
Sam Ravnborg 已提交
379
struct string_list *copy_node(struct string_list *node)
L
Linus Torvalds 已提交
380
{
S
Sam Ravnborg 已提交
381
	struct string_list *newnode;
L
Linus Torvalds 已提交
382

S
Sam Ravnborg 已提交
383 384 385
	newnode = xmalloc(sizeof(*newnode));
	newnode->string = xstrdup(node->string);
	newnode->tag = node->tag;
L
Linus Torvalds 已提交
386

S
Sam Ravnborg 已提交
387
	return newnode;
L
Linus Torvalds 已提交
388 389
}

390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405
struct string_list *copy_list_range(struct string_list *start,
				    struct string_list *end)
{
	struct string_list *res, *n;

	if (start == end)
		return NULL;
	n = res = copy_node(start);
	for (start = start->next; start != end; start = start->next) {
		n->next = copy_node(start);
		n = n->next;
	}
	n->next = NULL;
	return res;
}

S
Sam Ravnborg 已提交
406
static int equal_list(struct string_list *a, struct string_list *b)
L
Linus Torvalds 已提交
407
{
S
Sam Ravnborg 已提交
408 409 410 411 412 413
	while (a && b) {
		if (a->tag != b->tag || strcmp(a->string, b->string))
			return 0;
		a = a->next;
		b = b->next;
	}
L
Linus Torvalds 已提交
414

S
Sam Ravnborg 已提交
415
	return !a && !b;
L
Linus Torvalds 已提交
416 417
}

418 419
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))

420
static struct string_list *read_node(FILE *f)
421 422 423 424 425
{
	char buffer[256];
	struct string_list node = {
		.string = buffer,
		.tag = SYM_NORMAL };
426
	int c, in_string = 0;
427 428

	while ((c = fgetc(f)) != EOF) {
429
		if (!in_string && c == ' ') {
430 431 432
			if (node.string == buffer)
				continue;
			break;
433 434
		} else if (c == '"') {
			in_string = !in_string;
435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452
		} else if (c == '\n') {
			if (node.string == buffer)
				return NULL;
			ungetc(c, f);
			break;
		}
		if (node.string >= buffer + sizeof(buffer) - 1) {
			fprintf(stderr, "Token too long\n");
			exit(1);
		}
		*node.string++ = c;
	}
	if (node.string == buffer)
		return NULL;
	*node.string = 0;
	node.string = buffer;

	if (node.string[1] == '#') {
453
		size_t n;
454

455 456
		for (n = 0; n < ARRAY_SIZE(symbol_types); n++) {
			if (node.string[0] == symbol_types[n].n) {
457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472
				node.tag = n;
				node.string += 2;
				return copy_node(&node);
			}
		}
		fprintf(stderr, "Unknown type %c\n", node.string[0]);
		exit(1);
	}
	return copy_node(&node);
}

static void read_reference(FILE *f)
{
	while (!feof(f)) {
		struct string_list *defn = NULL;
		struct string_list *sym, *def;
473 474
		int is_extern = 0, is_override = 0;
		struct symbol *subsym;
475 476

		sym = read_node(f);
477 478 479 480 481 482
		if (sym && sym->tag == SYM_NORMAL &&
		    !strcmp(sym->string, "override")) {
			is_override = 1;
			free_node(sym);
			sym = read_node(f);
		}
483 484 485 486 487 488 489 490 491 492 493 494 495 496
		if (!sym)
			continue;
		def = read_node(f);
		if (def && def->tag == SYM_NORMAL &&
		    !strcmp(def->string, "extern")) {
			is_extern = 1;
			free_node(def);
			def = read_node(f);
		}
		while (def) {
			def->next = defn;
			defn = def;
			def = read_node(f);
		}
497
		subsym = add_reference_symbol(xstrdup(sym->string), sym->tag,
498
					      defn, is_extern);
499
		subsym->is_override = is_override;
500 501 502 503
		free_node(sym);
	}
}

S
Sam Ravnborg 已提交
504
static void print_node(FILE * f, struct string_list *list)
L
Linus Torvalds 已提交
505
{
506 507
	if (symbol_types[list->tag].n) {
		putc(symbol_types[list->tag].n, f);
S
Sam Ravnborg 已提交
508 509
		putc('#', f);
	}
510
	fputs(list->string, f);
L
Linus Torvalds 已提交
511 512
}

S
Sam Ravnborg 已提交
513
static void print_list(FILE * f, struct string_list *list)
L
Linus Torvalds 已提交
514
{
S
Sam Ravnborg 已提交
515 516 517
	struct string_list **e, **b;
	struct string_list *tmp, **tmp2;
	int elem = 1;
L
Linus Torvalds 已提交
518

S
Sam Ravnborg 已提交
519 520 521 522
	if (list == NULL) {
		fputs("(nil)", f);
		return;
	}
L
Linus Torvalds 已提交
523

S
Sam Ravnborg 已提交
524 525 526
	tmp = list;
	while ((tmp = tmp->next) != NULL)
		elem++;
L
Linus Torvalds 已提交
527

S
Sam Ravnborg 已提交
528 529 530
	b = alloca(elem * sizeof(*e));
	e = b + elem;
	tmp2 = e - 1;
L
Linus Torvalds 已提交
531

S
Sam Ravnborg 已提交
532 533 534
	(*tmp2--) = list;
	while ((list = list->next) != NULL)
		*(tmp2--) = list;
L
Linus Torvalds 已提交
535

S
Sam Ravnborg 已提交
536 537 538 539 540
	while (b != e) {
		print_node(f, *b++);
		putc(' ', f);
	}
}
L
Linus Torvalds 已提交
541

542
static unsigned long expand_and_crc_sym(struct symbol *sym, unsigned long crc)
S
Sam Ravnborg 已提交
543
{
544
	struct string_list *list = sym->defn;
S
Sam Ravnborg 已提交
545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576
	struct string_list **e, **b;
	struct string_list *tmp, **tmp2;
	int elem = 1;

	if (!list)
		return crc;

	tmp = list;
	while ((tmp = tmp->next) != NULL)
		elem++;

	b = alloca(elem * sizeof(*e));
	e = b + elem;
	tmp2 = e - 1;

	*(tmp2--) = list;
	while ((list = list->next) != NULL)
		*(tmp2--) = list;

	while (b != e) {
		struct string_list *cur;
		struct symbol *subsym;

		cur = *(b++);
		switch (cur->tag) {
		case SYM_NORMAL:
			if (flag_dump_defs)
				fprintf(debugfile, "%s ", cur->string);
			crc = partial_crc32(cur->string, crc);
			crc = partial_crc32_one(' ', crc);
			break;

577
		case SYM_ENUM_CONST:
S
Sam Ravnborg 已提交
578
		case SYM_TYPEDEF:
579
			subsym = find_symbol(cur->string, cur->tag, 0);
580
			/* FIXME: Bad reference files can segfault here. */
S
Sam Ravnborg 已提交
581 582 583 584 585 586 587 588
			if (subsym->expansion_trail) {
				if (flag_dump_defs)
					fprintf(debugfile, "%s ", cur->string);
				crc = partial_crc32(cur->string, crc);
				crc = partial_crc32_one(' ', crc);
			} else {
				subsym->expansion_trail = expansion_trail;
				expansion_trail = subsym;
589
				crc = expand_and_crc_sym(subsym, crc);
S
Sam Ravnborg 已提交
590 591 592 593 594 595
			}
			break;

		case SYM_STRUCT:
		case SYM_UNION:
		case SYM_ENUM:
596
			subsym = find_symbol(cur->string, cur->tag, 0);
S
Sam Ravnborg 已提交
597
			if (!subsym) {
598
				struct string_list *n;
S
Sam Ravnborg 已提交
599 600

				error_with_pos("expand undefined %s %s",
601
					       symbol_types[cur->tag].name,
S
Sam Ravnborg 已提交
602
					       cur->string);
603 604 605 606 607 608
				n = concat_list(mk_node
						(symbol_types[cur->tag].name),
						mk_node(cur->string),
						mk_node("{"),
						mk_node("UNKNOWN"),
						mk_node("}"), NULL);
S
Sam Ravnborg 已提交
609 610 611 612 613 614
				subsym =
				    add_symbol(cur->string, cur->tag, n, 0);
			}
			if (subsym->expansion_trail) {
				if (flag_dump_defs) {
					fprintf(debugfile, "%s %s ",
615
						symbol_types[cur->tag].name,
S
Sam Ravnborg 已提交
616 617 618
						cur->string);
				}

619
				crc = partial_crc32(symbol_types[cur->tag].name,
S
Sam Ravnborg 已提交
620
						    crc);
S
Sam Ravnborg 已提交
621 622 623 624 625 626
				crc = partial_crc32_one(' ', crc);
				crc = partial_crc32(cur->string, crc);
				crc = partial_crc32_one(' ', crc);
			} else {
				subsym->expansion_trail = expansion_trail;
				expansion_trail = subsym;
627
				crc = expand_and_crc_sym(subsym, crc);
S
Sam Ravnborg 已提交
628 629
			}
			break;
L
Linus Torvalds 已提交
630 631 632
		}
	}

633 634 635 636 637 638 639 640 641 642
	{
		static struct symbol **end = &visited_symbols;

		if (!sym->visited) {
			*end = sym;
			end = &sym->visited;
			sym->visited = (struct symbol *)-1L;
		}
	}

S
Sam Ravnborg 已提交
643
	return crc;
L
Linus Torvalds 已提交
644 645
}

S
Sam Ravnborg 已提交
646
void export_symbol(const char *name)
L
Linus Torvalds 已提交
647
{
S
Sam Ravnborg 已提交
648
	struct symbol *sym;
L
Linus Torvalds 已提交
649

650
	sym = find_symbol(name, SYM_NORMAL, 0);
S
Sam Ravnborg 已提交
651 652 653 654
	if (!sym)
		error_with_pos("export undefined symbol %s", name);
	else {
		unsigned long crc;
655
		int has_changed = 0;
L
Linus Torvalds 已提交
656

S
Sam Ravnborg 已提交
657 658
		if (flag_dump_defs)
			fprintf(debugfile, "Export %s == <", name);
L
Linus Torvalds 已提交
659

S
Sam Ravnborg 已提交
660
		expansion_trail = (struct symbol *)-1L;
L
Linus Torvalds 已提交
661

662 663
		sym->expansion_trail = expansion_trail;
		expansion_trail = sym;
664
		crc = expand_and_crc_sym(sym, 0xffffffff) ^ 0xffffffff;
L
Linus Torvalds 已提交
665

S
Sam Ravnborg 已提交
666 667 668
		sym = expansion_trail;
		while (sym != (struct symbol *)-1L) {
			struct symbol *n = sym->expansion_trail;
669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685

			if (sym->status != STATUS_UNCHANGED) {
				if (!has_changed) {
					print_location();
					fprintf(stderr, "%s: %s: modversion "
						"changed because of changes "
						"in ", flag_preserve ? "error" :
						       "warning", name);
				} else
					fprintf(stderr, ", ");
				print_type_name(sym->type, sym->name);
				if (sym->status == STATUS_DEFINED)
					fprintf(stderr, " (became defined)");
				has_changed = 1;
				if (flag_preserve)
					errors++;
			}
S
Sam Ravnborg 已提交
686 687 688
			sym->expansion_trail = 0;
			sym = n;
		}
689 690
		if (has_changed)
			fprintf(stderr, "\n");
L
Linus Torvalds 已提交
691

S
Sam Ravnborg 已提交
692 693
		if (flag_dump_defs)
			fputs(">\n", debugfile);
L
Linus Torvalds 已提交
694

695 696
		/* Used as a linker script. */
		printf("%s__crc_%s = 0x%08lx ;\n", mod_prefix, name, crc);
S
Sam Ravnborg 已提交
697
	}
L
Linus Torvalds 已提交
698 699 700
}

/*----------------------------------------------------------------------*/
701 702 703 704 705 706 707 708

static void print_location(void)
{
	fprintf(stderr, "%s:%d: ", cur_filename ? : "<stdin>", cur_line);
}

static void print_type_name(enum symbol_type type, const char *name)
{
709 710
	if (symbol_types[type].name)
		fprintf(stderr, "%s %s", symbol_types[type].name, name);
711 712 713 714
	else
		fprintf(stderr, "%s", name);
}

S
Sam Ravnborg 已提交
715
void error_with_pos(const char *fmt, ...)
L
Linus Torvalds 已提交
716
{
S
Sam Ravnborg 已提交
717
	va_list args;
L
Linus Torvalds 已提交
718

S
Sam Ravnborg 已提交
719
	if (flag_warnings) {
720
		print_location();
L
Linus Torvalds 已提交
721

S
Sam Ravnborg 已提交
722 723 724 725
		va_start(args, fmt);
		vfprintf(stderr, fmt, args);
		va_end(args);
		putc('\n', stderr);
L
Linus Torvalds 已提交
726

S
Sam Ravnborg 已提交
727 728
		errors++;
	}
L
Linus Torvalds 已提交
729 730
}

S
Sam Ravnborg 已提交
731
static void genksyms_usage(void)
L
Linus Torvalds 已提交
732
{
733
	fputs("Usage:\n" "genksyms [-adDTwqhV] > /path/to/.tmp_obj.ver\n" "\n"
L
Linus Torvalds 已提交
734
#ifdef __GNU_LIBRARY__
735
	      "  -s, --symbol-prefix   Select symbol prefix\n"
L
Linus Torvalds 已提交
736 737
	      "  -d, --debug           Increment the debug level (repeatable)\n"
	      "  -D, --dump            Dump expanded symbol defs (for debugging only)\n"
738 739 740
	      "  -r, --reference file  Read reference symbols from a file\n"
	      "  -T, --dump-types file Dump expanded types into file\n"
	      "  -p, --preserve        Preserve reference modversions or fail\n"
L
Linus Torvalds 已提交
741 742 743 744
	      "  -w, --warnings        Enable warnings\n"
	      "  -q, --quiet           Disable warnings (default)\n"
	      "  -h, --help            Print this message\n"
	      "  -V, --version         Print the release version\n"
S
Sam Ravnborg 已提交
745
#else				/* __GNU_LIBRARY__ */
746
	      "  -s                    Select symbol prefix\n"
S
Sam Ravnborg 已提交
747 748
	      "  -d                    Increment the debug level (repeatable)\n"
	      "  -D                    Dump expanded symbol defs (for debugging only)\n"
749 750 751
	      "  -r file               Read reference symbols from a file\n"
	      "  -T file               Dump expanded types into file\n"
	      "  -p                    Preserve reference modversions or fail\n"
S
Sam Ravnborg 已提交
752 753 754 755 756
	      "  -w                    Enable warnings\n"
	      "  -q                    Disable warnings (default)\n"
	      "  -h                    Print this message\n"
	      "  -V                    Print the release version\n"
#endif				/* __GNU_LIBRARY__ */
L
Linus Torvalds 已提交
757 758 759
	      , stderr);
}

S
Sam Ravnborg 已提交
760
int main(int argc, char **argv)
L
Linus Torvalds 已提交
761
{
762
	FILE *dumpfile = NULL, *ref_file = NULL;
S
Sam Ravnborg 已提交
763
	int o;
L
Linus Torvalds 已提交
764 765

#ifdef __GNU_LIBRARY__
S
Sam Ravnborg 已提交
766
	struct option long_opts[] = {
767
		{"symbol-prefix", 1, 0, 's'},
S
Sam Ravnborg 已提交
768 769 770 771
		{"debug", 0, 0, 'd'},
		{"warnings", 0, 0, 'w'},
		{"quiet", 0, 0, 'q'},
		{"dump", 0, 0, 'D'},
772
		{"reference", 1, 0, 'r'},
773
		{"dump-types", 1, 0, 'T'},
774
		{"preserve", 0, 0, 'p'},
S
Sam Ravnborg 已提交
775 776 777 778 779
		{"version", 0, 0, 'V'},
		{"help", 0, 0, 'h'},
		{0, 0, 0, 0}
	};

780
	while ((o = getopt_long(argc, argv, "s:dwqVDr:T:ph",
S
Sam Ravnborg 已提交
781 782
				&long_opts[0], NULL)) != EOF)
#else				/* __GNU_LIBRARY__ */
783
	while ((o = getopt(argc, argv, "s:dwqVDr:T:ph")) != EOF)
S
Sam Ravnborg 已提交
784 785
#endif				/* __GNU_LIBRARY__ */
		switch (o) {
786 787
		case 's':
			mod_prefix = optarg;
S
Sam Ravnborg 已提交
788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803
			break;
		case 'd':
			flag_debug++;
			break;
		case 'w':
			flag_warnings = 1;
			break;
		case 'q':
			flag_warnings = 0;
			break;
		case 'V':
			fputs("genksyms version 2.5.60\n", stderr);
			break;
		case 'D':
			flag_dump_defs = 1;
			break;
804 805 806 807 808 809 810 811
		case 'r':
			flag_reference = 1;
			ref_file = fopen(optarg, "r");
			if (!ref_file) {
				perror(optarg);
				return 1;
			}
			break;
812 813 814 815 816 817 818 819
		case 'T':
			flag_dump_types = 1;
			dumpfile = fopen(optarg, "w");
			if (!dumpfile) {
				perror(optarg);
				return 1;
			}
			break;
820 821 822
		case 'p':
			flag_preserve = 1;
			break;
S
Sam Ravnborg 已提交
823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840
		case 'h':
			genksyms_usage();
			return 0;
		default:
			genksyms_usage();
			return 1;
		}
	{
		extern int yydebug;
		extern int yy_flex_debug;

		yydebug = (flag_debug > 1);
		yy_flex_debug = (flag_debug > 2);

		debugfile = stderr;
		/* setlinebuf(debugfile); */
	}

841
	if (flag_reference) {
842
		read_reference(ref_file);
843 844
		fclose(ref_file);
	}
845

S
Sam Ravnborg 已提交
846 847
	yyparse();

848 849 850 851
	if (flag_dump_types && visited_symbols) {
		while (visited_symbols != (struct symbol *)-1L) {
			struct symbol *sym = visited_symbols;

852 853
			if (sym->is_override)
				fputs("override ", dumpfile);
854 855
			if (symbol_types[sym->type].n) {
				putc(symbol_types[sym->type].n, dumpfile);
856 857 858 859
				putc('#', dumpfile);
			}
			fputs(sym->name, dumpfile);
			putc(' ', dumpfile);
860 861
			if (sym->is_extern)
				fputs("extern ", dumpfile);
862 863 864 865 866 867 868 869
			print_list(dumpfile, sym->defn);
			putc('\n', dumpfile);

			visited_symbols = sym->visited;
			sym->visited = NULL;
		}
	}

S
Sam Ravnborg 已提交
870 871 872 873 874 875
	if (flag_debug) {
		fprintf(debugfile, "Hash table occupancy %d/%d = %g\n",
			nsyms, HASH_BUCKETS,
			(double)nsyms / (double)HASH_BUCKETS);
	}

876 877 878
	if (dumpfile)
		fclose(dumpfile);

S
Sam Ravnborg 已提交
879
	return errors != 0;
L
Linus Torvalds 已提交
880
}