xref: /openbmc/linux/scripts/genksyms/genksyms.c (revision 060f35a317ef09101b128f399dce7ed13d019461)
11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /* Generate kernel symbol version hashes.
31da177e4SLinus Torvalds    Copyright 1996, 1997 Linux International.
41da177e4SLinus Torvalds 
51da177e4SLinus Torvalds    New implementation contributed by Richard Henderson <rth@tamu.edu>
61da177e4SLinus Torvalds    Based on original work by Bjorn Ekwall <bj0rn@blox.se>
71da177e4SLinus Torvalds 
81da177e4SLinus Torvalds    This file was part of the Linux modutils 2.4.22: moved back into the
91da177e4SLinus Torvalds    kernel sources by Rusty Russell/Kai Germaschewski.
101da177e4SLinus Torvalds 
111a59d1b8SThomas Gleixner  */
121da177e4SLinus Torvalds 
131da177e4SLinus Torvalds #include <stdio.h>
141da177e4SLinus Torvalds #include <string.h>
151da177e4SLinus Torvalds #include <stdlib.h>
161da177e4SLinus Torvalds #include <unistd.h>
171da177e4SLinus Torvalds #include <assert.h>
181da177e4SLinus Torvalds #include <stdarg.h>
191da177e4SLinus Torvalds #ifdef __GNU_LIBRARY__
201da177e4SLinus Torvalds #include <getopt.h>
211da177e4SLinus Torvalds #endif				/* __GNU_LIBRARY__ */
221da177e4SLinus Torvalds 
231da177e4SLinus Torvalds #include "genksyms.h"
241da177e4SLinus Torvalds /*----------------------------------------------------------------------*/
251da177e4SLinus Torvalds 
261da177e4SLinus Torvalds #define HASH_BUCKETS  4096
271da177e4SLinus Torvalds 
281da177e4SLinus Torvalds static struct symbol *symtab[HASH_BUCKETS];
29ce560686SSam Ravnborg static FILE *debugfile;
301da177e4SLinus Torvalds 
311da177e4SLinus Torvalds int cur_line = 1;
32ab37d5a4SMasahiro Yamada char *cur_filename;
332c5925d6SMichal Marek int in_source_file;
341da177e4SLinus Torvalds 
3564e6c1e1SAndreas Gruenbacher static int flag_debug, flag_dump_defs, flag_reference, flag_dump_types,
367b453719SMasahiro Yamada 	   flag_preserve, flag_warnings;
371da177e4SLinus Torvalds 
381da177e4SLinus Torvalds static int errors;
391da177e4SLinus Torvalds static int nsyms;
401da177e4SLinus Torvalds 
411da177e4SLinus Torvalds static struct symbol *expansion_trail;
4215fde675SAndreas Gruenbacher static struct symbol *visited_symbols;
431da177e4SLinus Torvalds 
447ec8eda1SMichal Marek static const struct {
457ec8eda1SMichal Marek 	int n;
467ec8eda1SMichal Marek 	const char *name;
477ec8eda1SMichal Marek } symbol_types[] = {
487ec8eda1SMichal Marek 	[SYM_NORMAL]     = { 0, NULL},
497ec8eda1SMichal Marek 	[SYM_TYPEDEF]    = {'t', "typedef"},
507ec8eda1SMichal Marek 	[SYM_ENUM]       = {'e', "enum"},
517ec8eda1SMichal Marek 	[SYM_STRUCT]     = {'s', "struct"},
527ec8eda1SMichal Marek 	[SYM_UNION]      = {'u', "union"},
53e37ddb82SMichal Marek 	[SYM_ENUM_CONST] = {'E', "enum constant"},
541da177e4SLinus Torvalds };
551da177e4SLinus Torvalds 
56ce560686SSam Ravnborg static int equal_list(struct string_list *a, struct string_list *b);
57ce560686SSam Ravnborg static void print_list(FILE * f, struct string_list *list);
5868eb8563SMichal Marek static struct string_list *concat_list(struct string_list *start, ...);
5968eb8563SMichal Marek static struct string_list *mk_node(const char *string);
6064e6c1e1SAndreas Gruenbacher static void print_location(void);
6164e6c1e1SAndreas Gruenbacher static void print_type_name(enum symbol_type type, const char *name);
62ce560686SSam Ravnborg 
631da177e4SLinus Torvalds /*----------------------------------------------------------------------*/
641da177e4SLinus Torvalds 
6578c04153SSam Ravnborg static const unsigned int crctab32[] = {
661da177e4SLinus Torvalds 	0x00000000U, 0x77073096U, 0xee0e612cU, 0x990951baU, 0x076dc419U,
671da177e4SLinus Torvalds 	0x706af48fU, 0xe963a535U, 0x9e6495a3U, 0x0edb8832U, 0x79dcb8a4U,
681da177e4SLinus Torvalds 	0xe0d5e91eU, 0x97d2d988U, 0x09b64c2bU, 0x7eb17cbdU, 0xe7b82d07U,
691da177e4SLinus Torvalds 	0x90bf1d91U, 0x1db71064U, 0x6ab020f2U, 0xf3b97148U, 0x84be41deU,
701da177e4SLinus Torvalds 	0x1adad47dU, 0x6ddde4ebU, 0xf4d4b551U, 0x83d385c7U, 0x136c9856U,
711da177e4SLinus Torvalds 	0x646ba8c0U, 0xfd62f97aU, 0x8a65c9ecU, 0x14015c4fU, 0x63066cd9U,
721da177e4SLinus Torvalds 	0xfa0f3d63U, 0x8d080df5U, 0x3b6e20c8U, 0x4c69105eU, 0xd56041e4U,
731da177e4SLinus Torvalds 	0xa2677172U, 0x3c03e4d1U, 0x4b04d447U, 0xd20d85fdU, 0xa50ab56bU,
741da177e4SLinus Torvalds 	0x35b5a8faU, 0x42b2986cU, 0xdbbbc9d6U, 0xacbcf940U, 0x32d86ce3U,
751da177e4SLinus Torvalds 	0x45df5c75U, 0xdcd60dcfU, 0xabd13d59U, 0x26d930acU, 0x51de003aU,
761da177e4SLinus Torvalds 	0xc8d75180U, 0xbfd06116U, 0x21b4f4b5U, 0x56b3c423U, 0xcfba9599U,
771da177e4SLinus Torvalds 	0xb8bda50fU, 0x2802b89eU, 0x5f058808U, 0xc60cd9b2U, 0xb10be924U,
781da177e4SLinus Torvalds 	0x2f6f7c87U, 0x58684c11U, 0xc1611dabU, 0xb6662d3dU, 0x76dc4190U,
791da177e4SLinus Torvalds 	0x01db7106U, 0x98d220bcU, 0xefd5102aU, 0x71b18589U, 0x06b6b51fU,
801da177e4SLinus Torvalds 	0x9fbfe4a5U, 0xe8b8d433U, 0x7807c9a2U, 0x0f00f934U, 0x9609a88eU,
811da177e4SLinus Torvalds 	0xe10e9818U, 0x7f6a0dbbU, 0x086d3d2dU, 0x91646c97U, 0xe6635c01U,
821da177e4SLinus Torvalds 	0x6b6b51f4U, 0x1c6c6162U, 0x856530d8U, 0xf262004eU, 0x6c0695edU,
831da177e4SLinus Torvalds 	0x1b01a57bU, 0x8208f4c1U, 0xf50fc457U, 0x65b0d9c6U, 0x12b7e950U,
841da177e4SLinus Torvalds 	0x8bbeb8eaU, 0xfcb9887cU, 0x62dd1ddfU, 0x15da2d49U, 0x8cd37cf3U,
851da177e4SLinus Torvalds 	0xfbd44c65U, 0x4db26158U, 0x3ab551ceU, 0xa3bc0074U, 0xd4bb30e2U,
861da177e4SLinus Torvalds 	0x4adfa541U, 0x3dd895d7U, 0xa4d1c46dU, 0xd3d6f4fbU, 0x4369e96aU,
871da177e4SLinus Torvalds 	0x346ed9fcU, 0xad678846U, 0xda60b8d0U, 0x44042d73U, 0x33031de5U,
881da177e4SLinus Torvalds 	0xaa0a4c5fU, 0xdd0d7cc9U, 0x5005713cU, 0x270241aaU, 0xbe0b1010U,
891da177e4SLinus Torvalds 	0xc90c2086U, 0x5768b525U, 0x206f85b3U, 0xb966d409U, 0xce61e49fU,
901da177e4SLinus Torvalds 	0x5edef90eU, 0x29d9c998U, 0xb0d09822U, 0xc7d7a8b4U, 0x59b33d17U,
911da177e4SLinus Torvalds 	0x2eb40d81U, 0xb7bd5c3bU, 0xc0ba6cadU, 0xedb88320U, 0x9abfb3b6U,
921da177e4SLinus Torvalds 	0x03b6e20cU, 0x74b1d29aU, 0xead54739U, 0x9dd277afU, 0x04db2615U,
931da177e4SLinus Torvalds 	0x73dc1683U, 0xe3630b12U, 0x94643b84U, 0x0d6d6a3eU, 0x7a6a5aa8U,
941da177e4SLinus Torvalds 	0xe40ecf0bU, 0x9309ff9dU, 0x0a00ae27U, 0x7d079eb1U, 0xf00f9344U,
951da177e4SLinus Torvalds 	0x8708a3d2U, 0x1e01f268U, 0x6906c2feU, 0xf762575dU, 0x806567cbU,
961da177e4SLinus Torvalds 	0x196c3671U, 0x6e6b06e7U, 0xfed41b76U, 0x89d32be0U, 0x10da7a5aU,
971da177e4SLinus Torvalds 	0x67dd4accU, 0xf9b9df6fU, 0x8ebeeff9U, 0x17b7be43U, 0x60b08ed5U,
981da177e4SLinus Torvalds 	0xd6d6a3e8U, 0xa1d1937eU, 0x38d8c2c4U, 0x4fdff252U, 0xd1bb67f1U,
991da177e4SLinus Torvalds 	0xa6bc5767U, 0x3fb506ddU, 0x48b2364bU, 0xd80d2bdaU, 0xaf0a1b4cU,
1001da177e4SLinus Torvalds 	0x36034af6U, 0x41047a60U, 0xdf60efc3U, 0xa867df55U, 0x316e8eefU,
1011da177e4SLinus Torvalds 	0x4669be79U, 0xcb61b38cU, 0xbc66831aU, 0x256fd2a0U, 0x5268e236U,
1021da177e4SLinus Torvalds 	0xcc0c7795U, 0xbb0b4703U, 0x220216b9U, 0x5505262fU, 0xc5ba3bbeU,
1031da177e4SLinus Torvalds 	0xb2bd0b28U, 0x2bb45a92U, 0x5cb36a04U, 0xc2d7ffa7U, 0xb5d0cf31U,
1041da177e4SLinus Torvalds 	0x2cd99e8bU, 0x5bdeae1dU, 0x9b64c2b0U, 0xec63f226U, 0x756aa39cU,
1051da177e4SLinus Torvalds 	0x026d930aU, 0x9c0906a9U, 0xeb0e363fU, 0x72076785U, 0x05005713U,
1061da177e4SLinus Torvalds 	0x95bf4a82U, 0xe2b87a14U, 0x7bb12baeU, 0x0cb61b38U, 0x92d28e9bU,
1071da177e4SLinus Torvalds 	0xe5d5be0dU, 0x7cdcefb7U, 0x0bdbdf21U, 0x86d3d2d4U, 0xf1d4e242U,
1081da177e4SLinus Torvalds 	0x68ddb3f8U, 0x1fda836eU, 0x81be16cdU, 0xf6b9265bU, 0x6fb077e1U,
1091da177e4SLinus Torvalds 	0x18b74777U, 0x88085ae6U, 0xff0f6a70U, 0x66063bcaU, 0x11010b5cU,
1101da177e4SLinus Torvalds 	0x8f659effU, 0xf862ae69U, 0x616bffd3U, 0x166ccf45U, 0xa00ae278U,
1111da177e4SLinus Torvalds 	0xd70dd2eeU, 0x4e048354U, 0x3903b3c2U, 0xa7672661U, 0xd06016f7U,
1121da177e4SLinus Torvalds 	0x4969474dU, 0x3e6e77dbU, 0xaed16a4aU, 0xd9d65adcU, 0x40df0b66U,
1131da177e4SLinus Torvalds 	0x37d83bf0U, 0xa9bcae53U, 0xdebb9ec5U, 0x47b2cf7fU, 0x30b5ffe9U,
1141da177e4SLinus Torvalds 	0xbdbdf21cU, 0xcabac28aU, 0x53b39330U, 0x24b4a3a6U, 0xbad03605U,
1151da177e4SLinus Torvalds 	0xcdd70693U, 0x54de5729U, 0x23d967bfU, 0xb3667a2eU, 0xc4614ab8U,
1161da177e4SLinus Torvalds 	0x5d681b02U, 0x2a6f2b94U, 0xb40bbe37U, 0xc30c8ea1U, 0x5a05df1bU,
1171da177e4SLinus Torvalds 	0x2d02ef8dU
1181da177e4SLinus Torvalds };
1191da177e4SLinus Torvalds 
partial_crc32_one(unsigned char c,unsigned long crc)120ce560686SSam Ravnborg static unsigned long partial_crc32_one(unsigned char c, unsigned long crc)
1211da177e4SLinus Torvalds {
1221da177e4SLinus Torvalds 	return crctab32[(crc ^ c) & 0xff] ^ (crc >> 8);
1231da177e4SLinus Torvalds }
1241da177e4SLinus Torvalds 
partial_crc32(const char * s,unsigned long crc)125ce560686SSam Ravnborg static unsigned long partial_crc32(const char *s, unsigned long crc)
1261da177e4SLinus Torvalds {
1271da177e4SLinus Torvalds 	while (*s)
1281da177e4SLinus Torvalds 		crc = partial_crc32_one(*s++, crc);
1291da177e4SLinus Torvalds 	return crc;
1301da177e4SLinus Torvalds }
1311da177e4SLinus Torvalds 
crc32(const char * s)132ce560686SSam Ravnborg static unsigned long crc32(const char *s)
1331da177e4SLinus Torvalds {
1341da177e4SLinus Torvalds 	return partial_crc32(s, 0xffffffff) ^ 0xffffffff;
1351da177e4SLinus Torvalds }
1361da177e4SLinus Torvalds 
1371da177e4SLinus Torvalds /*----------------------------------------------------------------------*/
1381da177e4SLinus Torvalds 
map_to_ns(enum symbol_type t)139ce560686SSam Ravnborg static enum symbol_type map_to_ns(enum symbol_type t)
1401da177e4SLinus Torvalds {
141e37ddb82SMichal Marek 	switch (t) {
142e37ddb82SMichal Marek 	case SYM_ENUM_CONST:
143e37ddb82SMichal Marek 	case SYM_NORMAL:
144e37ddb82SMichal Marek 	case SYM_TYPEDEF:
145e37ddb82SMichal Marek 		return SYM_NORMAL;
146e37ddb82SMichal Marek 	case SYM_ENUM:
147e37ddb82SMichal Marek 	case SYM_STRUCT:
148e37ddb82SMichal Marek 	case SYM_UNION:
149e37ddb82SMichal Marek 		return SYM_STRUCT;
150e37ddb82SMichal Marek 	}
1511da177e4SLinus Torvalds 	return t;
1521da177e4SLinus Torvalds }
1531da177e4SLinus Torvalds 
find_symbol(const char * name,enum symbol_type ns,int exact)15401762c4eSMichal Marek struct symbol *find_symbol(const char *name, enum symbol_type ns, int exact)
1551da177e4SLinus Torvalds {
1561da177e4SLinus Torvalds 	unsigned long h = crc32(name) % HASH_BUCKETS;
1571da177e4SLinus Torvalds 	struct symbol *sym;
1581da177e4SLinus Torvalds 
1591da177e4SLinus Torvalds 	for (sym = symtab[h]; sym; sym = sym->hash_next)
160ce560686SSam Ravnborg 		if (map_to_ns(sym->type) == map_to_ns(ns) &&
16164e6c1e1SAndreas Gruenbacher 		    strcmp(name, sym->name) == 0 &&
16264e6c1e1SAndreas Gruenbacher 		    sym->is_declared)
1631da177e4SLinus Torvalds 			break;
1641da177e4SLinus Torvalds 
16501762c4eSMichal Marek 	if (exact && sym && sym->type != ns)
16601762c4eSMichal Marek 		return NULL;
1671da177e4SLinus Torvalds 	return sym;
1681da177e4SLinus Torvalds }
1691da177e4SLinus Torvalds 
is_unknown_symbol(struct symbol * sym)17064e6c1e1SAndreas Gruenbacher static int is_unknown_symbol(struct symbol *sym)
17164e6c1e1SAndreas Gruenbacher {
17264e6c1e1SAndreas Gruenbacher 	struct string_list *defn;
17364e6c1e1SAndreas Gruenbacher 
17464e6c1e1SAndreas Gruenbacher 	return ((sym->type == SYM_STRUCT ||
17564e6c1e1SAndreas Gruenbacher 		 sym->type == SYM_UNION ||
17664e6c1e1SAndreas Gruenbacher 		 sym->type == SYM_ENUM) &&
17764e6c1e1SAndreas Gruenbacher 		(defn = sym->defn)  && defn->tag == SYM_NORMAL &&
17864e6c1e1SAndreas Gruenbacher 			strcmp(defn->string, "}") == 0 &&
17964e6c1e1SAndreas Gruenbacher 		(defn = defn->next) && defn->tag == SYM_NORMAL &&
18064e6c1e1SAndreas Gruenbacher 			strcmp(defn->string, "UNKNOWN") == 0 &&
18164e6c1e1SAndreas Gruenbacher 		(defn = defn->next) && defn->tag == SYM_NORMAL &&
18264e6c1e1SAndreas Gruenbacher 			strcmp(defn->string, "{") == 0);
18364e6c1e1SAndreas Gruenbacher }
18464e6c1e1SAndreas Gruenbacher 
__add_symbol(const char * name,enum symbol_type type,struct string_list * defn,int is_extern,int is_reference)185b7ed698cSLadinu Chandrasinghe static struct symbol *__add_symbol(const char *name, enum symbol_type type,
18664e6c1e1SAndreas Gruenbacher 			    struct string_list *defn, int is_extern,
18764e6c1e1SAndreas Gruenbacher 			    int is_reference)
1881da177e4SLinus Torvalds {
189e37ddb82SMichal Marek 	unsigned long h;
1901da177e4SLinus Torvalds 	struct symbol *sym;
19164e6c1e1SAndreas Gruenbacher 	enum symbol_status status = STATUS_UNCHANGED;
192e37ddb82SMichal Marek 	/* The parser adds symbols in the order their declaration completes,
193e37ddb82SMichal Marek 	 * so it is safe to store the value of the previous enum constant in
194e37ddb82SMichal Marek 	 * a static variable.
195e37ddb82SMichal Marek 	 */
196e37ddb82SMichal Marek 	static int enum_counter;
197e37ddb82SMichal Marek 	static struct string_list *last_enum_expr;
1981da177e4SLinus Torvalds 
199e37ddb82SMichal Marek 	if (type == SYM_ENUM_CONST) {
200e37ddb82SMichal Marek 		if (defn) {
201e37ddb82SMichal Marek 			free_list(last_enum_expr, NULL);
202e37ddb82SMichal Marek 			last_enum_expr = copy_list_range(defn, NULL);
203e37ddb82SMichal Marek 			enum_counter = 1;
204e37ddb82SMichal Marek 		} else {
205e37ddb82SMichal Marek 			struct string_list *expr;
206e37ddb82SMichal Marek 			char buf[20];
207e37ddb82SMichal Marek 
208e37ddb82SMichal Marek 			snprintf(buf, sizeof(buf), "%d", enum_counter++);
209e37ddb82SMichal Marek 			if (last_enum_expr) {
210e37ddb82SMichal Marek 				expr = copy_list_range(last_enum_expr, NULL);
211e37ddb82SMichal Marek 				defn = concat_list(mk_node("("),
212e37ddb82SMichal Marek 						   expr,
213e37ddb82SMichal Marek 						   mk_node(")"),
214e37ddb82SMichal Marek 						   mk_node("+"),
215e37ddb82SMichal Marek 						   mk_node(buf), NULL);
216e37ddb82SMichal Marek 			} else {
217e37ddb82SMichal Marek 				defn = mk_node(buf);
218e37ddb82SMichal Marek 			}
219e37ddb82SMichal Marek 		}
220e37ddb82SMichal Marek 	} else if (type == SYM_ENUM) {
221e37ddb82SMichal Marek 		free_list(last_enum_expr, NULL);
222e37ddb82SMichal Marek 		last_enum_expr = NULL;
223e37ddb82SMichal Marek 		enum_counter = 0;
224e37ddb82SMichal Marek 		if (!name)
225e37ddb82SMichal Marek 			/* Anonymous enum definition, nothing more to do */
226e37ddb82SMichal Marek 			return NULL;
227e37ddb82SMichal Marek 	}
228e37ddb82SMichal Marek 
229e37ddb82SMichal Marek 	h = crc32(name) % HASH_BUCKETS;
230ce560686SSam Ravnborg 	for (sym = symtab[h]; sym; sym = sym->hash_next) {
23164e6c1e1SAndreas Gruenbacher 		if (map_to_ns(sym->type) == map_to_ns(type) &&
23264e6c1e1SAndreas Gruenbacher 		    strcmp(name, sym->name) == 0) {
23364e6c1e1SAndreas Gruenbacher 			if (is_reference)
23464e6c1e1SAndreas Gruenbacher 				/* fall through */ ;
23564e6c1e1SAndreas Gruenbacher 			else if (sym->type == type &&
23664e6c1e1SAndreas Gruenbacher 				 equal_list(sym->defn, defn)) {
2375dae9a55SAndreas Gruenbacher 				if (!sym->is_declared && sym->is_override) {
2385dae9a55SAndreas Gruenbacher 					print_location();
2395dae9a55SAndreas Gruenbacher 					print_type_name(type, name);
2405dae9a55SAndreas Gruenbacher 					fprintf(stderr, " modversion is "
2415dae9a55SAndreas Gruenbacher 						"unchanged\n");
2425dae9a55SAndreas Gruenbacher 				}
24364e6c1e1SAndreas Gruenbacher 				sym->is_declared = 1;
2449dc841e8SMasahiro Yamada 				free_list(defn, NULL);
24564e6c1e1SAndreas Gruenbacher 				return sym;
24664e6c1e1SAndreas Gruenbacher 			} else if (!sym->is_declared) {
2475dae9a55SAndreas Gruenbacher 				if (sym->is_override && flag_preserve) {
2485dae9a55SAndreas Gruenbacher 					print_location();
2495dae9a55SAndreas Gruenbacher 					fprintf(stderr, "ignoring ");
2505dae9a55SAndreas Gruenbacher 					print_type_name(type, name);
2515dae9a55SAndreas Gruenbacher 					fprintf(stderr, " modversion change\n");
2525dae9a55SAndreas Gruenbacher 					sym->is_declared = 1;
2539dc841e8SMasahiro Yamada 					free_list(defn, NULL);
2545dae9a55SAndreas Gruenbacher 					return sym;
2555dae9a55SAndreas Gruenbacher 				} else {
25664e6c1e1SAndreas Gruenbacher 					status = is_unknown_symbol(sym) ?
25764e6c1e1SAndreas Gruenbacher 						STATUS_DEFINED : STATUS_MODIFIED;
2585dae9a55SAndreas Gruenbacher 				}
25964e6c1e1SAndreas Gruenbacher 			} else {
2601da177e4SLinus Torvalds 				error_with_pos("redefinition of %s", name);
2619dc841e8SMasahiro Yamada 				free_list(defn, NULL);
2621da177e4SLinus Torvalds 				return sym;
2631da177e4SLinus Torvalds 			}
26464e6c1e1SAndreas Gruenbacher 			break;
26564e6c1e1SAndreas Gruenbacher 		}
26664e6c1e1SAndreas Gruenbacher 	}
26764e6c1e1SAndreas Gruenbacher 
26864e6c1e1SAndreas Gruenbacher 	if (sym) {
26964e6c1e1SAndreas Gruenbacher 		struct symbol **psym;
27064e6c1e1SAndreas Gruenbacher 
27164e6c1e1SAndreas Gruenbacher 		for (psym = &symtab[h]; *psym; psym = &(*psym)->hash_next) {
27264e6c1e1SAndreas Gruenbacher 			if (*psym == sym) {
27364e6c1e1SAndreas Gruenbacher 				*psym = sym->hash_next;
27464e6c1e1SAndreas Gruenbacher 				break;
27564e6c1e1SAndreas Gruenbacher 			}
27664e6c1e1SAndreas Gruenbacher 		}
277*4517f37bSMasahiro Yamada 
278*4517f37bSMasahiro Yamada 		free_list(sym->defn, NULL);
279*4517f37bSMasahiro Yamada 		free(sym->name);
280*4517f37bSMasahiro Yamada 		free(sym);
28164e6c1e1SAndreas Gruenbacher 		--nsyms;
282ce560686SSam Ravnborg 	}
2831da177e4SLinus Torvalds 
2841da177e4SLinus Torvalds 	sym = xmalloc(sizeof(*sym));
285*4517f37bSMasahiro Yamada 	sym->name = xstrdup(name);
2861da177e4SLinus Torvalds 	sym->type = type;
2871da177e4SLinus Torvalds 	sym->defn = defn;
2881da177e4SLinus Torvalds 	sym->expansion_trail = NULL;
28915fde675SAndreas Gruenbacher 	sym->visited = NULL;
2901da177e4SLinus Torvalds 	sym->is_extern = is_extern;
2911da177e4SLinus Torvalds 
2921da177e4SLinus Torvalds 	sym->hash_next = symtab[h];
2931da177e4SLinus Torvalds 	symtab[h] = sym;
2941da177e4SLinus Torvalds 
29564e6c1e1SAndreas Gruenbacher 	sym->is_declared = !is_reference;
29664e6c1e1SAndreas Gruenbacher 	sym->status = status;
2975dae9a55SAndreas Gruenbacher 	sym->is_override = 0;
29864e6c1e1SAndreas Gruenbacher 
29978c04153SSam Ravnborg 	if (flag_debug) {
3007ec8eda1SMichal Marek 		if (symbol_types[type].name)
30178c04153SSam Ravnborg 			fprintf(debugfile, "Defn for %s %s == <",
3027ec8eda1SMichal Marek 				symbol_types[type].name, name);
3037ec8eda1SMichal Marek 		else
3047ec8eda1SMichal Marek 			fprintf(debugfile, "Defn for type%d %s == <",
3057ec8eda1SMichal Marek 				type, name);
3061da177e4SLinus Torvalds 		if (is_extern)
3071da177e4SLinus Torvalds 			fputs("extern ", debugfile);
3081da177e4SLinus Torvalds 		print_list(debugfile, defn);
3091da177e4SLinus Torvalds 		fputs(">\n", debugfile);
3101da177e4SLinus Torvalds 	}
3111da177e4SLinus Torvalds 
3121da177e4SLinus Torvalds 	++nsyms;
3131da177e4SLinus Torvalds 	return sym;
3141da177e4SLinus Torvalds }
3151da177e4SLinus Torvalds 
add_symbol(const char * name,enum symbol_type type,struct string_list * defn,int is_extern)31664e6c1e1SAndreas Gruenbacher struct symbol *add_symbol(const char *name, enum symbol_type type,
31764e6c1e1SAndreas Gruenbacher 			  struct string_list *defn, int is_extern)
31864e6c1e1SAndreas Gruenbacher {
31964e6c1e1SAndreas Gruenbacher 	return __add_symbol(name, type, defn, is_extern, 0);
32064e6c1e1SAndreas Gruenbacher }
32164e6c1e1SAndreas Gruenbacher 
add_reference_symbol(const char * name,enum symbol_type type,struct string_list * defn,int is_extern)322b7ed698cSLadinu Chandrasinghe static struct symbol *add_reference_symbol(const char *name, enum symbol_type type,
32364e6c1e1SAndreas Gruenbacher 				    struct string_list *defn, int is_extern)
32464e6c1e1SAndreas Gruenbacher {
32564e6c1e1SAndreas Gruenbacher 	return __add_symbol(name, type, defn, is_extern, 1);
32664e6c1e1SAndreas Gruenbacher }
32764e6c1e1SAndreas Gruenbacher 
3281da177e4SLinus Torvalds /*----------------------------------------------------------------------*/
3291da177e4SLinus Torvalds 
free_node(struct string_list * node)330ce560686SSam Ravnborg void free_node(struct string_list *node)
3311da177e4SLinus Torvalds {
3321da177e4SLinus Torvalds 	free(node->string);
3331da177e4SLinus Torvalds 	free(node);
3341da177e4SLinus Torvalds }
3351da177e4SLinus Torvalds 
free_list(struct string_list * s,struct string_list * e)33678c04153SSam Ravnborg void free_list(struct string_list *s, struct string_list *e)
3371da177e4SLinus Torvalds {
33878c04153SSam Ravnborg 	while (s != e) {
3391da177e4SLinus Torvalds 		struct string_list *next = s->next;
3401da177e4SLinus Torvalds 		free_node(s);
3411da177e4SLinus Torvalds 		s = next;
3421da177e4SLinus Torvalds 	}
3431da177e4SLinus Torvalds }
3441da177e4SLinus Torvalds 
mk_node(const char * string)34568eb8563SMichal Marek static struct string_list *mk_node(const char *string)
34668eb8563SMichal Marek {
34768eb8563SMichal Marek 	struct string_list *newnode;
34868eb8563SMichal Marek 
34968eb8563SMichal Marek 	newnode = xmalloc(sizeof(*newnode));
35068eb8563SMichal Marek 	newnode->string = xstrdup(string);
35168eb8563SMichal Marek 	newnode->tag = SYM_NORMAL;
35268eb8563SMichal Marek 	newnode->next = NULL;
35368eb8563SMichal Marek 
35468eb8563SMichal Marek 	return newnode;
35568eb8563SMichal Marek }
35668eb8563SMichal Marek 
concat_list(struct string_list * start,...)35768eb8563SMichal Marek static struct string_list *concat_list(struct string_list *start, ...)
35868eb8563SMichal Marek {
35968eb8563SMichal Marek 	va_list ap;
36068eb8563SMichal Marek 	struct string_list *n, *n2;
36168eb8563SMichal Marek 
36268eb8563SMichal Marek 	if (!start)
36368eb8563SMichal Marek 		return NULL;
36468eb8563SMichal Marek 	for (va_start(ap, start); (n = va_arg(ap, struct string_list *));) {
36568eb8563SMichal Marek 		for (n2 = n; n2->next; n2 = n2->next)
36668eb8563SMichal Marek 			;
36768eb8563SMichal Marek 		n2->next = start;
36868eb8563SMichal Marek 		start = n;
36968eb8563SMichal Marek 	}
37068eb8563SMichal Marek 	va_end(ap);
37168eb8563SMichal Marek 	return start;
37268eb8563SMichal Marek }
37368eb8563SMichal Marek 
copy_node(struct string_list * node)374ce560686SSam Ravnborg struct string_list *copy_node(struct string_list *node)
3751da177e4SLinus Torvalds {
3761da177e4SLinus Torvalds 	struct string_list *newnode;
3771da177e4SLinus Torvalds 
3781da177e4SLinus Torvalds 	newnode = xmalloc(sizeof(*newnode));
3791da177e4SLinus Torvalds 	newnode->string = xstrdup(node->string);
3801da177e4SLinus Torvalds 	newnode->tag = node->tag;
3811da177e4SLinus Torvalds 
3821da177e4SLinus Torvalds 	return newnode;
3831da177e4SLinus Torvalds }
3841da177e4SLinus Torvalds 
copy_list_range(struct string_list * start,struct string_list * end)385e37ddb82SMichal Marek struct string_list *copy_list_range(struct string_list *start,
386e37ddb82SMichal Marek 				    struct string_list *end)
387e37ddb82SMichal Marek {
388e37ddb82SMichal Marek 	struct string_list *res, *n;
389e37ddb82SMichal Marek 
390e37ddb82SMichal Marek 	if (start == end)
391e37ddb82SMichal Marek 		return NULL;
392e37ddb82SMichal Marek 	n = res = copy_node(start);
393e37ddb82SMichal Marek 	for (start = start->next; start != end; start = start->next) {
394e37ddb82SMichal Marek 		n->next = copy_node(start);
395e37ddb82SMichal Marek 		n = n->next;
396e37ddb82SMichal Marek 	}
397e37ddb82SMichal Marek 	n->next = NULL;
398e37ddb82SMichal Marek 	return res;
399e37ddb82SMichal Marek }
400e37ddb82SMichal Marek 
equal_list(struct string_list * a,struct string_list * b)401ce560686SSam Ravnborg static int equal_list(struct string_list *a, struct string_list *b)
4021da177e4SLinus Torvalds {
40378c04153SSam Ravnborg 	while (a && b) {
4041da177e4SLinus Torvalds 		if (a->tag != b->tag || strcmp(a->string, b->string))
4051da177e4SLinus Torvalds 			return 0;
4061da177e4SLinus Torvalds 		a = a->next;
4071da177e4SLinus Torvalds 		b = b->next;
4081da177e4SLinus Torvalds 	}
4091da177e4SLinus Torvalds 
4101da177e4SLinus Torvalds 	return !a && !b;
4111da177e4SLinus Torvalds }
4121da177e4SLinus Torvalds 
41364e6c1e1SAndreas Gruenbacher #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
41464e6c1e1SAndreas Gruenbacher 
read_node(FILE * f)415b7ed698cSLadinu Chandrasinghe static struct string_list *read_node(FILE *f)
41664e6c1e1SAndreas Gruenbacher {
41764e6c1e1SAndreas Gruenbacher 	char buffer[256];
41864e6c1e1SAndreas Gruenbacher 	struct string_list node = {
41964e6c1e1SAndreas Gruenbacher 		.string = buffer,
42064e6c1e1SAndreas Gruenbacher 		.tag = SYM_NORMAL };
421a78f70e8SMichal Marek 	int c, in_string = 0;
42264e6c1e1SAndreas Gruenbacher 
42364e6c1e1SAndreas Gruenbacher 	while ((c = fgetc(f)) != EOF) {
424a78f70e8SMichal Marek 		if (!in_string && c == ' ') {
42564e6c1e1SAndreas Gruenbacher 			if (node.string == buffer)
42664e6c1e1SAndreas Gruenbacher 				continue;
42764e6c1e1SAndreas Gruenbacher 			break;
428a78f70e8SMichal Marek 		} else if (c == '"') {
429a78f70e8SMichal Marek 			in_string = !in_string;
43064e6c1e1SAndreas Gruenbacher 		} else if (c == '\n') {
43164e6c1e1SAndreas Gruenbacher 			if (node.string == buffer)
43264e6c1e1SAndreas Gruenbacher 				return NULL;
43364e6c1e1SAndreas Gruenbacher 			ungetc(c, f);
43464e6c1e1SAndreas Gruenbacher 			break;
43564e6c1e1SAndreas Gruenbacher 		}
43664e6c1e1SAndreas Gruenbacher 		if (node.string >= buffer + sizeof(buffer) - 1) {
43764e6c1e1SAndreas Gruenbacher 			fprintf(stderr, "Token too long\n");
43864e6c1e1SAndreas Gruenbacher 			exit(1);
43964e6c1e1SAndreas Gruenbacher 		}
44064e6c1e1SAndreas Gruenbacher 		*node.string++ = c;
44164e6c1e1SAndreas Gruenbacher 	}
44264e6c1e1SAndreas Gruenbacher 	if (node.string == buffer)
44364e6c1e1SAndreas Gruenbacher 		return NULL;
44464e6c1e1SAndreas Gruenbacher 	*node.string = 0;
44564e6c1e1SAndreas Gruenbacher 	node.string = buffer;
44664e6c1e1SAndreas Gruenbacher 
44764e6c1e1SAndreas Gruenbacher 	if (node.string[1] == '#') {
4481ae14703SJesper Juhl 		size_t n;
44964e6c1e1SAndreas Gruenbacher 
4507ec8eda1SMichal Marek 		for (n = 0; n < ARRAY_SIZE(symbol_types); n++) {
4517ec8eda1SMichal Marek 			if (node.string[0] == symbol_types[n].n) {
45264e6c1e1SAndreas Gruenbacher 				node.tag = n;
45364e6c1e1SAndreas Gruenbacher 				node.string += 2;
45464e6c1e1SAndreas Gruenbacher 				return copy_node(&node);
45564e6c1e1SAndreas Gruenbacher 			}
45664e6c1e1SAndreas Gruenbacher 		}
45764e6c1e1SAndreas Gruenbacher 		fprintf(stderr, "Unknown type %c\n", node.string[0]);
45864e6c1e1SAndreas Gruenbacher 		exit(1);
45964e6c1e1SAndreas Gruenbacher 	}
46064e6c1e1SAndreas Gruenbacher 	return copy_node(&node);
46164e6c1e1SAndreas Gruenbacher }
46264e6c1e1SAndreas Gruenbacher 
read_reference(FILE * f)46364e6c1e1SAndreas Gruenbacher static void read_reference(FILE *f)
46464e6c1e1SAndreas Gruenbacher {
46564e6c1e1SAndreas Gruenbacher 	while (!feof(f)) {
46664e6c1e1SAndreas Gruenbacher 		struct string_list *defn = NULL;
46764e6c1e1SAndreas Gruenbacher 		struct string_list *sym, *def;
4685dae9a55SAndreas Gruenbacher 		int is_extern = 0, is_override = 0;
4695dae9a55SAndreas Gruenbacher 		struct symbol *subsym;
47064e6c1e1SAndreas Gruenbacher 
47164e6c1e1SAndreas Gruenbacher 		sym = read_node(f);
4725dae9a55SAndreas Gruenbacher 		if (sym && sym->tag == SYM_NORMAL &&
4735dae9a55SAndreas Gruenbacher 		    !strcmp(sym->string, "override")) {
4745dae9a55SAndreas Gruenbacher 			is_override = 1;
4755dae9a55SAndreas Gruenbacher 			free_node(sym);
4765dae9a55SAndreas Gruenbacher 			sym = read_node(f);
4775dae9a55SAndreas Gruenbacher 		}
47864e6c1e1SAndreas Gruenbacher 		if (!sym)
47964e6c1e1SAndreas Gruenbacher 			continue;
48064e6c1e1SAndreas Gruenbacher 		def = read_node(f);
48164e6c1e1SAndreas Gruenbacher 		if (def && def->tag == SYM_NORMAL &&
48264e6c1e1SAndreas Gruenbacher 		    !strcmp(def->string, "extern")) {
48364e6c1e1SAndreas Gruenbacher 			is_extern = 1;
48464e6c1e1SAndreas Gruenbacher 			free_node(def);
48564e6c1e1SAndreas Gruenbacher 			def = read_node(f);
48664e6c1e1SAndreas Gruenbacher 		}
48764e6c1e1SAndreas Gruenbacher 		while (def) {
48864e6c1e1SAndreas Gruenbacher 			def->next = defn;
48964e6c1e1SAndreas Gruenbacher 			defn = def;
49064e6c1e1SAndreas Gruenbacher 			def = read_node(f);
49164e6c1e1SAndreas Gruenbacher 		}
492*4517f37bSMasahiro Yamada 		subsym = add_reference_symbol(sym->string, sym->tag,
49364e6c1e1SAndreas Gruenbacher 					      defn, is_extern);
4945dae9a55SAndreas Gruenbacher 		subsym->is_override = is_override;
49564e6c1e1SAndreas Gruenbacher 		free_node(sym);
49664e6c1e1SAndreas Gruenbacher 	}
49764e6c1e1SAndreas Gruenbacher }
49864e6c1e1SAndreas Gruenbacher 
print_node(FILE * f,struct string_list * list)499ce560686SSam Ravnborg static void print_node(FILE * f, struct string_list *list)
5001da177e4SLinus Torvalds {
5017ec8eda1SMichal Marek 	if (symbol_types[list->tag].n) {
5027ec8eda1SMichal Marek 		putc(symbol_types[list->tag].n, f);
5031da177e4SLinus Torvalds 		putc('#', f);
5041da177e4SLinus Torvalds 	}
50515fde675SAndreas Gruenbacher 	fputs(list->string, f);
5061da177e4SLinus Torvalds }
5071da177e4SLinus Torvalds 
print_list(FILE * f,struct string_list * list)508ce560686SSam Ravnborg static void print_list(FILE * f, struct string_list *list)
5091da177e4SLinus Torvalds {
5101da177e4SLinus Torvalds 	struct string_list **e, **b;
5111da177e4SLinus Torvalds 	struct string_list *tmp, **tmp2;
5121da177e4SLinus Torvalds 	int elem = 1;
5131da177e4SLinus Torvalds 
51478c04153SSam Ravnborg 	if (list == NULL) {
5151da177e4SLinus Torvalds 		fputs("(nil)", f);
5161da177e4SLinus Torvalds 		return;
5171da177e4SLinus Torvalds 	}
5181da177e4SLinus Torvalds 
5191da177e4SLinus Torvalds 	tmp = list;
5201da177e4SLinus Torvalds 	while ((tmp = tmp->next) != NULL)
5211da177e4SLinus Torvalds 		elem++;
5221da177e4SLinus Torvalds 
5231da177e4SLinus Torvalds 	b = alloca(elem * sizeof(*e));
5241da177e4SLinus Torvalds 	e = b + elem;
5251da177e4SLinus Torvalds 	tmp2 = e - 1;
5261da177e4SLinus Torvalds 
5271da177e4SLinus Torvalds 	(*tmp2--) = list;
5281da177e4SLinus Torvalds 	while ((list = list->next) != NULL)
5291da177e4SLinus Torvalds 		*(tmp2--) = list;
5301da177e4SLinus Torvalds 
53178c04153SSam Ravnborg 	while (b != e) {
5321da177e4SLinus Torvalds 		print_node(f, *b++);
5331da177e4SLinus Torvalds 		putc(' ', f);
5341da177e4SLinus Torvalds 	}
5351da177e4SLinus Torvalds }
5361da177e4SLinus Torvalds 
expand_and_crc_sym(struct symbol * sym,unsigned long crc)53715fde675SAndreas Gruenbacher static unsigned long expand_and_crc_sym(struct symbol *sym, unsigned long crc)
5381da177e4SLinus Torvalds {
53915fde675SAndreas Gruenbacher 	struct string_list *list = sym->defn;
5401da177e4SLinus Torvalds 	struct string_list **e, **b;
5411da177e4SLinus Torvalds 	struct string_list *tmp, **tmp2;
5421da177e4SLinus Torvalds 	int elem = 1;
5431da177e4SLinus Torvalds 
5441da177e4SLinus Torvalds 	if (!list)
5451da177e4SLinus Torvalds 		return crc;
5461da177e4SLinus Torvalds 
5471da177e4SLinus Torvalds 	tmp = list;
5481da177e4SLinus Torvalds 	while ((tmp = tmp->next) != NULL)
5491da177e4SLinus Torvalds 		elem++;
5501da177e4SLinus Torvalds 
5511da177e4SLinus Torvalds 	b = alloca(elem * sizeof(*e));
5521da177e4SLinus Torvalds 	e = b + elem;
5531da177e4SLinus Torvalds 	tmp2 = e - 1;
5541da177e4SLinus Torvalds 
5551da177e4SLinus Torvalds 	*(tmp2--) = list;
5561da177e4SLinus Torvalds 	while ((list = list->next) != NULL)
5571da177e4SLinus Torvalds 		*(tmp2--) = list;
5581da177e4SLinus Torvalds 
55978c04153SSam Ravnborg 	while (b != e) {
5601da177e4SLinus Torvalds 		struct string_list *cur;
5611da177e4SLinus Torvalds 		struct symbol *subsym;
5621da177e4SLinus Torvalds 
5631da177e4SLinus Torvalds 		cur = *(b++);
56478c04153SSam Ravnborg 		switch (cur->tag) {
5651da177e4SLinus Torvalds 		case SYM_NORMAL:
5661da177e4SLinus Torvalds 			if (flag_dump_defs)
5671da177e4SLinus Torvalds 				fprintf(debugfile, "%s ", cur->string);
5681da177e4SLinus Torvalds 			crc = partial_crc32(cur->string, crc);
5691da177e4SLinus Torvalds 			crc = partial_crc32_one(' ', crc);
5701da177e4SLinus Torvalds 			break;
5711da177e4SLinus Torvalds 
572e37ddb82SMichal Marek 		case SYM_ENUM_CONST:
5731da177e4SLinus Torvalds 		case SYM_TYPEDEF:
57401762c4eSMichal Marek 			subsym = find_symbol(cur->string, cur->tag, 0);
57564e6c1e1SAndreas Gruenbacher 			/* FIXME: Bad reference files can segfault here. */
57678c04153SSam Ravnborg 			if (subsym->expansion_trail) {
5771da177e4SLinus Torvalds 				if (flag_dump_defs)
5781da177e4SLinus Torvalds 					fprintf(debugfile, "%s ", cur->string);
5791da177e4SLinus Torvalds 				crc = partial_crc32(cur->string, crc);
5801da177e4SLinus Torvalds 				crc = partial_crc32_one(' ', crc);
58178c04153SSam Ravnborg 			} else {
5821da177e4SLinus Torvalds 				subsym->expansion_trail = expansion_trail;
5831da177e4SLinus Torvalds 				expansion_trail = subsym;
58415fde675SAndreas Gruenbacher 				crc = expand_and_crc_sym(subsym, crc);
5851da177e4SLinus Torvalds 			}
5861da177e4SLinus Torvalds 			break;
5871da177e4SLinus Torvalds 
5881da177e4SLinus Torvalds 		case SYM_STRUCT:
5891da177e4SLinus Torvalds 		case SYM_UNION:
5901da177e4SLinus Torvalds 		case SYM_ENUM:
59101762c4eSMichal Marek 			subsym = find_symbol(cur->string, cur->tag, 0);
59278c04153SSam Ravnborg 			if (!subsym) {
59368eb8563SMichal Marek 				struct string_list *n;
5941da177e4SLinus Torvalds 
5951da177e4SLinus Torvalds 				error_with_pos("expand undefined %s %s",
5967ec8eda1SMichal Marek 					       symbol_types[cur->tag].name,
59778c04153SSam Ravnborg 					       cur->string);
59868eb8563SMichal Marek 				n = concat_list(mk_node
59968eb8563SMichal Marek 						(symbol_types[cur->tag].name),
60068eb8563SMichal Marek 						mk_node(cur->string),
60168eb8563SMichal Marek 						mk_node("{"),
60268eb8563SMichal Marek 						mk_node("UNKNOWN"),
60368eb8563SMichal Marek 						mk_node("}"), NULL);
60478c04153SSam Ravnborg 				subsym =
60578c04153SSam Ravnborg 				    add_symbol(cur->string, cur->tag, n, 0);
6061da177e4SLinus Torvalds 			}
60778c04153SSam Ravnborg 			if (subsym->expansion_trail) {
60878c04153SSam Ravnborg 				if (flag_dump_defs) {
60978c04153SSam Ravnborg 					fprintf(debugfile, "%s %s ",
6107ec8eda1SMichal Marek 						symbol_types[cur->tag].name,
6111da177e4SLinus Torvalds 						cur->string);
6121da177e4SLinus Torvalds 				}
6131da177e4SLinus Torvalds 
6147ec8eda1SMichal Marek 				crc = partial_crc32(symbol_types[cur->tag].name,
61578c04153SSam Ravnborg 						    crc);
6161da177e4SLinus Torvalds 				crc = partial_crc32_one(' ', crc);
6171da177e4SLinus Torvalds 				crc = partial_crc32(cur->string, crc);
6181da177e4SLinus Torvalds 				crc = partial_crc32_one(' ', crc);
61978c04153SSam Ravnborg 			} else {
6201da177e4SLinus Torvalds 				subsym->expansion_trail = expansion_trail;
6211da177e4SLinus Torvalds 				expansion_trail = subsym;
62215fde675SAndreas Gruenbacher 				crc = expand_and_crc_sym(subsym, crc);
6231da177e4SLinus Torvalds 			}
6241da177e4SLinus Torvalds 			break;
6251da177e4SLinus Torvalds 		}
6261da177e4SLinus Torvalds 	}
6271da177e4SLinus Torvalds 
62815fde675SAndreas Gruenbacher 	{
62915fde675SAndreas Gruenbacher 		static struct symbol **end = &visited_symbols;
63015fde675SAndreas Gruenbacher 
63115fde675SAndreas Gruenbacher 		if (!sym->visited) {
63215fde675SAndreas Gruenbacher 			*end = sym;
63315fde675SAndreas Gruenbacher 			end = &sym->visited;
63415fde675SAndreas Gruenbacher 			sym->visited = (struct symbol *)-1L;
63515fde675SAndreas Gruenbacher 		}
63615fde675SAndreas Gruenbacher 	}
63715fde675SAndreas Gruenbacher 
6381da177e4SLinus Torvalds 	return crc;
6391da177e4SLinus Torvalds }
6401da177e4SLinus Torvalds 
export_symbol(const char * name)64178c04153SSam Ravnborg void export_symbol(const char *name)
6421da177e4SLinus Torvalds {
6431da177e4SLinus Torvalds 	struct symbol *sym;
6441da177e4SLinus Torvalds 
64501762c4eSMichal Marek 	sym = find_symbol(name, SYM_NORMAL, 0);
6461da177e4SLinus Torvalds 	if (!sym)
6471da177e4SLinus Torvalds 		error_with_pos("export undefined symbol %s", name);
64878c04153SSam Ravnborg 	else {
6491da177e4SLinus Torvalds 		unsigned long crc;
65064e6c1e1SAndreas Gruenbacher 		int has_changed = 0;
6511da177e4SLinus Torvalds 
6521da177e4SLinus Torvalds 		if (flag_dump_defs)
6531da177e4SLinus Torvalds 			fprintf(debugfile, "Export %s == <", name);
6541da177e4SLinus Torvalds 
6551da177e4SLinus Torvalds 		expansion_trail = (struct symbol *)-1L;
6561da177e4SLinus Torvalds 
65764e6c1e1SAndreas Gruenbacher 		sym->expansion_trail = expansion_trail;
65864e6c1e1SAndreas Gruenbacher 		expansion_trail = sym;
65915fde675SAndreas Gruenbacher 		crc = expand_and_crc_sym(sym, 0xffffffff) ^ 0xffffffff;
6601da177e4SLinus Torvalds 
6611da177e4SLinus Torvalds 		sym = expansion_trail;
66278c04153SSam Ravnborg 		while (sym != (struct symbol *)-1L) {
6631da177e4SLinus Torvalds 			struct symbol *n = sym->expansion_trail;
66464e6c1e1SAndreas Gruenbacher 
66564e6c1e1SAndreas Gruenbacher 			if (sym->status != STATUS_UNCHANGED) {
66664e6c1e1SAndreas Gruenbacher 				if (!has_changed) {
66764e6c1e1SAndreas Gruenbacher 					print_location();
66864e6c1e1SAndreas Gruenbacher 					fprintf(stderr, "%s: %s: modversion "
66964e6c1e1SAndreas Gruenbacher 						"changed because of changes "
67064e6c1e1SAndreas Gruenbacher 						"in ", flag_preserve ? "error" :
67164e6c1e1SAndreas Gruenbacher 						       "warning", name);
67264e6c1e1SAndreas Gruenbacher 				} else
67364e6c1e1SAndreas Gruenbacher 					fprintf(stderr, ", ");
67464e6c1e1SAndreas Gruenbacher 				print_type_name(sym->type, sym->name);
67564e6c1e1SAndreas Gruenbacher 				if (sym->status == STATUS_DEFINED)
67664e6c1e1SAndreas Gruenbacher 					fprintf(stderr, " (became defined)");
67764e6c1e1SAndreas Gruenbacher 				has_changed = 1;
67864e6c1e1SAndreas Gruenbacher 				if (flag_preserve)
67964e6c1e1SAndreas Gruenbacher 					errors++;
68064e6c1e1SAndreas Gruenbacher 			}
6811da177e4SLinus Torvalds 			sym->expansion_trail = 0;
6821da177e4SLinus Torvalds 			sym = n;
6831da177e4SLinus Torvalds 		}
68464e6c1e1SAndreas Gruenbacher 		if (has_changed)
68564e6c1e1SAndreas Gruenbacher 			fprintf(stderr, "\n");
6861da177e4SLinus Torvalds 
6871da177e4SLinus Torvalds 		if (flag_dump_defs)
6881da177e4SLinus Torvalds 			fputs(">\n", debugfile);
6891da177e4SLinus Torvalds 
6905ce2176bSMasahiro Yamada 		printf("#SYMVER %s 0x%08lx\n", name, crc);
6911da177e4SLinus Torvalds 	}
6921da177e4SLinus Torvalds }
6931da177e4SLinus Torvalds 
6941da177e4SLinus Torvalds /*----------------------------------------------------------------------*/
69564e6c1e1SAndreas Gruenbacher 
print_location(void)69664e6c1e1SAndreas Gruenbacher static void print_location(void)
69764e6c1e1SAndreas Gruenbacher {
69864e6c1e1SAndreas Gruenbacher 	fprintf(stderr, "%s:%d: ", cur_filename ? : "<stdin>", cur_line);
69964e6c1e1SAndreas Gruenbacher }
70064e6c1e1SAndreas Gruenbacher 
print_type_name(enum symbol_type type,const char * name)70164e6c1e1SAndreas Gruenbacher static void print_type_name(enum symbol_type type, const char *name)
70264e6c1e1SAndreas Gruenbacher {
7037ec8eda1SMichal Marek 	if (symbol_types[type].name)
7047ec8eda1SMichal Marek 		fprintf(stderr, "%s %s", symbol_types[type].name, name);
70564e6c1e1SAndreas Gruenbacher 	else
70664e6c1e1SAndreas Gruenbacher 		fprintf(stderr, "%s", name);
70764e6c1e1SAndreas Gruenbacher }
70864e6c1e1SAndreas Gruenbacher 
error_with_pos(const char * fmt,...)70978c04153SSam Ravnborg void error_with_pos(const char *fmt, ...)
7101da177e4SLinus Torvalds {
7111da177e4SLinus Torvalds 	va_list args;
7121da177e4SLinus Torvalds 
71378c04153SSam Ravnborg 	if (flag_warnings) {
71464e6c1e1SAndreas Gruenbacher 		print_location();
7151da177e4SLinus Torvalds 
7161da177e4SLinus Torvalds 		va_start(args, fmt);
7171da177e4SLinus Torvalds 		vfprintf(stderr, fmt, args);
7181da177e4SLinus Torvalds 		va_end(args);
7191da177e4SLinus Torvalds 		putc('\n', stderr);
7201da177e4SLinus Torvalds 
7211da177e4SLinus Torvalds 		errors++;
7221da177e4SLinus Torvalds 	}
7231da177e4SLinus Torvalds }
7241da177e4SLinus Torvalds 
genksyms_usage(void)725ce560686SSam Ravnborg static void genksyms_usage(void)
7261da177e4SLinus Torvalds {
72756067812SArd Biesheuvel 	fputs("Usage:\n" "genksyms [-adDTwqhVR] > /path/to/.tmp_obj.ver\n" "\n"
7281da177e4SLinus Torvalds #ifdef __GNU_LIBRARY__
729d70f82acSJames Hogan 	      "  -s, --symbol-prefix   Select symbol prefix\n"
7301da177e4SLinus Torvalds 	      "  -d, --debug           Increment the debug level (repeatable)\n"
7311da177e4SLinus Torvalds 	      "  -D, --dump            Dump expanded symbol defs (for debugging only)\n"
73264e6c1e1SAndreas Gruenbacher 	      "  -r, --reference file  Read reference symbols from a file\n"
73364e6c1e1SAndreas Gruenbacher 	      "  -T, --dump-types file Dump expanded types into file\n"
73464e6c1e1SAndreas Gruenbacher 	      "  -p, --preserve        Preserve reference modversions or fail\n"
7351da177e4SLinus Torvalds 	      "  -w, --warnings        Enable warnings\n"
7361da177e4SLinus Torvalds 	      "  -q, --quiet           Disable warnings (default)\n"
7371da177e4SLinus Torvalds 	      "  -h, --help            Print this message\n"
7381da177e4SLinus Torvalds 	      "  -V, --version         Print the release version\n"
7391da177e4SLinus Torvalds #else				/* __GNU_LIBRARY__ */
740d70f82acSJames Hogan 	      "  -s                    Select symbol prefix\n"
7411da177e4SLinus Torvalds 	      "  -d                    Increment the debug level (repeatable)\n"
7421da177e4SLinus Torvalds 	      "  -D                    Dump expanded symbol defs (for debugging only)\n"
74364e6c1e1SAndreas Gruenbacher 	      "  -r file               Read reference symbols from a file\n"
74464e6c1e1SAndreas Gruenbacher 	      "  -T file               Dump expanded types into file\n"
74564e6c1e1SAndreas Gruenbacher 	      "  -p                    Preserve reference modversions or fail\n"
7461da177e4SLinus Torvalds 	      "  -w                    Enable warnings\n"
7471da177e4SLinus Torvalds 	      "  -q                    Disable warnings (default)\n"
7481da177e4SLinus Torvalds 	      "  -h                    Print this message\n"
7491da177e4SLinus Torvalds 	      "  -V                    Print the release version\n"
7501da177e4SLinus Torvalds #endif				/* __GNU_LIBRARY__ */
7511da177e4SLinus Torvalds 	      , stderr);
7521da177e4SLinus Torvalds }
7531da177e4SLinus Torvalds 
main(int argc,char ** argv)75478c04153SSam Ravnborg int main(int argc, char **argv)
7551da177e4SLinus Torvalds {
75664e6c1e1SAndreas Gruenbacher 	FILE *dumpfile = NULL, *ref_file = NULL;
7571da177e4SLinus Torvalds 	int o;
7581da177e4SLinus Torvalds 
7591da177e4SLinus Torvalds #ifdef __GNU_LIBRARY__
7601da177e4SLinus Torvalds 	struct option long_opts[] = {
7611da177e4SLinus Torvalds 		{"debug", 0, 0, 'd'},
7621da177e4SLinus Torvalds 		{"warnings", 0, 0, 'w'},
7631da177e4SLinus Torvalds 		{"quiet", 0, 0, 'q'},
7641da177e4SLinus Torvalds 		{"dump", 0, 0, 'D'},
76564e6c1e1SAndreas Gruenbacher 		{"reference", 1, 0, 'r'},
76615fde675SAndreas Gruenbacher 		{"dump-types", 1, 0, 'T'},
76764e6c1e1SAndreas Gruenbacher 		{"preserve", 0, 0, 'p'},
7681da177e4SLinus Torvalds 		{"version", 0, 0, 'V'},
7691da177e4SLinus Torvalds 		{"help", 0, 0, 'h'},
7701da177e4SLinus Torvalds 		{0, 0, 0, 0}
7711da177e4SLinus Torvalds 	};
7721da177e4SLinus Torvalds 
7737b453719SMasahiro Yamada 	while ((o = getopt_long(argc, argv, "s:dwqVDr:T:ph",
7741da177e4SLinus Torvalds 				&long_opts[0], NULL)) != EOF)
7751da177e4SLinus Torvalds #else				/* __GNU_LIBRARY__ */
7767b453719SMasahiro Yamada 	while ((o = getopt(argc, argv, "s:dwqVDr:T:ph")) != EOF)
7771da177e4SLinus Torvalds #endif				/* __GNU_LIBRARY__ */
77878c04153SSam Ravnborg 		switch (o) {
7791da177e4SLinus Torvalds 		case 'd':
7801da177e4SLinus Torvalds 			flag_debug++;
7811da177e4SLinus Torvalds 			break;
7821da177e4SLinus Torvalds 		case 'w':
7831da177e4SLinus Torvalds 			flag_warnings = 1;
7841da177e4SLinus Torvalds 			break;
7851da177e4SLinus Torvalds 		case 'q':
7861da177e4SLinus Torvalds 			flag_warnings = 0;
7871da177e4SLinus Torvalds 			break;
7881da177e4SLinus Torvalds 		case 'V':
7891da177e4SLinus Torvalds 			fputs("genksyms version 2.5.60\n", stderr);
7901da177e4SLinus Torvalds 			break;
7911da177e4SLinus Torvalds 		case 'D':
7921da177e4SLinus Torvalds 			flag_dump_defs = 1;
7931da177e4SLinus Torvalds 			break;
79464e6c1e1SAndreas Gruenbacher 		case 'r':
79564e6c1e1SAndreas Gruenbacher 			flag_reference = 1;
79664e6c1e1SAndreas Gruenbacher 			ref_file = fopen(optarg, "r");
79764e6c1e1SAndreas Gruenbacher 			if (!ref_file) {
79864e6c1e1SAndreas Gruenbacher 				perror(optarg);
79964e6c1e1SAndreas Gruenbacher 				return 1;
80064e6c1e1SAndreas Gruenbacher 			}
80164e6c1e1SAndreas Gruenbacher 			break;
80215fde675SAndreas Gruenbacher 		case 'T':
80315fde675SAndreas Gruenbacher 			flag_dump_types = 1;
80415fde675SAndreas Gruenbacher 			dumpfile = fopen(optarg, "w");
80515fde675SAndreas Gruenbacher 			if (!dumpfile) {
80615fde675SAndreas Gruenbacher 				perror(optarg);
80715fde675SAndreas Gruenbacher 				return 1;
80815fde675SAndreas Gruenbacher 			}
80915fde675SAndreas Gruenbacher 			break;
81064e6c1e1SAndreas Gruenbacher 		case 'p':
81164e6c1e1SAndreas Gruenbacher 			flag_preserve = 1;
81264e6c1e1SAndreas Gruenbacher 			break;
8131da177e4SLinus Torvalds 		case 'h':
8141da177e4SLinus Torvalds 			genksyms_usage();
8151da177e4SLinus Torvalds 			return 0;
8161da177e4SLinus Torvalds 		default:
8171da177e4SLinus Torvalds 			genksyms_usage();
8181da177e4SLinus Torvalds 			return 1;
8191da177e4SLinus Torvalds 		}
8201da177e4SLinus Torvalds 	{
8211da177e4SLinus Torvalds 		extern int yydebug;
8221da177e4SLinus Torvalds 		extern int yy_flex_debug;
8231da177e4SLinus Torvalds 
8241da177e4SLinus Torvalds 		yydebug = (flag_debug > 1);
8251da177e4SLinus Torvalds 		yy_flex_debug = (flag_debug > 2);
8261da177e4SLinus Torvalds 
8271da177e4SLinus Torvalds 		debugfile = stderr;
8281da177e4SLinus Torvalds 		/* setlinebuf(debugfile); */
8291da177e4SLinus Torvalds 	}
8301da177e4SLinus Torvalds 
831c64152bfSAlexander Beregalov 	if (flag_reference) {
83264e6c1e1SAndreas Gruenbacher 		read_reference(ref_file);
833c64152bfSAlexander Beregalov 		fclose(ref_file);
834c64152bfSAlexander Beregalov 	}
83564e6c1e1SAndreas Gruenbacher 
8361da177e4SLinus Torvalds 	yyparse();
8371da177e4SLinus Torvalds 
83815fde675SAndreas Gruenbacher 	if (flag_dump_types && visited_symbols) {
83915fde675SAndreas Gruenbacher 		while (visited_symbols != (struct symbol *)-1L) {
84015fde675SAndreas Gruenbacher 			struct symbol *sym = visited_symbols;
84115fde675SAndreas Gruenbacher 
8425dae9a55SAndreas Gruenbacher 			if (sym->is_override)
8435dae9a55SAndreas Gruenbacher 				fputs("override ", dumpfile);
8447ec8eda1SMichal Marek 			if (symbol_types[sym->type].n) {
8457ec8eda1SMichal Marek 				putc(symbol_types[sym->type].n, dumpfile);
84615fde675SAndreas Gruenbacher 				putc('#', dumpfile);
84715fde675SAndreas Gruenbacher 			}
84815fde675SAndreas Gruenbacher 			fputs(sym->name, dumpfile);
84915fde675SAndreas Gruenbacher 			putc(' ', dumpfile);
8503b40d381SAndreas Gruenbacher 			if (sym->is_extern)
8513b40d381SAndreas Gruenbacher 				fputs("extern ", dumpfile);
85215fde675SAndreas Gruenbacher 			print_list(dumpfile, sym->defn);
85315fde675SAndreas Gruenbacher 			putc('\n', dumpfile);
85415fde675SAndreas Gruenbacher 
85515fde675SAndreas Gruenbacher 			visited_symbols = sym->visited;
85615fde675SAndreas Gruenbacher 			sym->visited = NULL;
85715fde675SAndreas Gruenbacher 		}
85815fde675SAndreas Gruenbacher 	}
85915fde675SAndreas Gruenbacher 
86078c04153SSam Ravnborg 	if (flag_debug) {
8611da177e4SLinus Torvalds 		fprintf(debugfile, "Hash table occupancy %d/%d = %g\n",
86278c04153SSam Ravnborg 			nsyms, HASH_BUCKETS,
86378c04153SSam Ravnborg 			(double)nsyms / (double)HASH_BUCKETS);
8641da177e4SLinus Torvalds 	}
8651da177e4SLinus Torvalds 
8664deaaa4dSMaxim Zhukov 	if (dumpfile)
8674deaaa4dSMaxim Zhukov 		fclose(dumpfile);
8684deaaa4dSMaxim Zhukov 
8691da177e4SLinus Torvalds 	return errors != 0;
8701da177e4SLinus Torvalds }
871