mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	genksyms: track symbol checksum changes
Sometimes it is preferable to avoid changes of exported symbol checksums (to avoid breaking externally provided modules). When a checksum change occurs, it can be hard to figure out what caused this change: underlying types may have changed, or additional type information may simply have become available at the point where a symbol is exported. Add a new --reference option to genksyms which allows it to report why checksums change, based on the type information dumps it creates with the --dump-types flag. Genksyms will read in such a dump from a previous run, and report which symbols have changed (and why). The behavior can be controlled for an entire build as follows: If KBUILD_SYMTYPES is set, genksyms uses --dump-types to produce *.symtypes dump files. If any *.symref files exist, those will be used as the reference to check against. If KBUILD_PRESERVE is set, checksum changes will fail the build. Signed-off-by: Andreas Gruenbacher <agruen@suse.de> Cc: Randy Dunlap <randy.dunlap@oracle.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Sam Ravnborg <sam@ravnborg.org>
This commit is contained in:
		
							parent
							
								
									a680eedc6c
								
							
						
					
					
						commit
						64e6c1e123
					
				
					 3 changed files with 239 additions and 19 deletions
				
			
		| 
						 | 
					@ -153,12 +153,18 @@ $(obj)/%.i: $(src)/%.c FORCE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
quiet_cmd_cc_symtypes_c = SYM $(quiet_modtag) $@
 | 
					quiet_cmd_cc_symtypes_c = SYM $(quiet_modtag) $@
 | 
				
			||||||
cmd_cc_symtypes_c	   = \
 | 
					cmd_cc_symtypes_c	   = \
 | 
				
			||||||
 | 
							set -e;							\
 | 
				
			||||||
		$(CPP) -D__GENKSYMS__ $(c_flags) $<			\
 | 
							$(CPP) -D__GENKSYMS__ $(c_flags) $<			\
 | 
				
			||||||
		| $(GENKSYMS) -T $@ >/dev/null;				\
 | 
							| $(GENKSYMS) -T $@					\
 | 
				
			||||||
 | 
								      -r $(firstword $(wildcard			\
 | 
				
			||||||
 | 
									     $(@:.symtypes=.symref) /dev/null))	\
 | 
				
			||||||
 | 
								      $(if $(KBUILD_PRESERVE),-p)		\
 | 
				
			||||||
 | 
								      -a $(ARCH)				\
 | 
				
			||||||
 | 
							  >/dev/null;						\
 | 
				
			||||||
		test -s $@ || rm -f $@
 | 
							test -s $@ || rm -f $@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
$(obj)/%.symtypes : $(src)/%.c FORCE
 | 
					$(obj)/%.symtypes : $(src)/%.c FORCE
 | 
				
			||||||
	$(call if_changed_dep,cc_symtypes_c)
 | 
						$(call cmd,cc_symtypes_c)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# C (.c) files
 | 
					# C (.c) files
 | 
				
			||||||
# The C file is compiled and updated dependency information is generated.
 | 
					# The C file is compiled and updated dependency information is generated.
 | 
				
			||||||
| 
						 | 
					@ -187,7 +193,11 @@ cmd_modversions =							\
 | 
				
			||||||
	if $(OBJDUMP) -h $(@D)/.tmp_$(@F) | grep -q __ksymtab; then	\
 | 
						if $(OBJDUMP) -h $(@D)/.tmp_$(@F) | grep -q __ksymtab; then	\
 | 
				
			||||||
		$(CPP) -D__GENKSYMS__ $(c_flags) $<			\
 | 
							$(CPP) -D__GENKSYMS__ $(c_flags) $<			\
 | 
				
			||||||
		| $(GENKSYMS) $(if $(KBUILD_SYMTYPES),			\
 | 
							| $(GENKSYMS) $(if $(KBUILD_SYMTYPES),			\
 | 
				
			||||||
			      -T $(@D)/$(@F:.o=.symtypes)) -a $(ARCH)	\
 | 
								           -T $(@:.o=.symtypes))		\
 | 
				
			||||||
 | 
								      -r $(firstword $(wildcard			\
 | 
				
			||||||
 | 
									     $(@:.o=.symref) /dev/null))	\
 | 
				
			||||||
 | 
								      $(if $(KBUILD_PRESERVE),-p)		\
 | 
				
			||||||
 | 
								      -a $(ARCH)				\
 | 
				
			||||||
		> $(@D)/.tmp_$(@F:.o=.ver);				\
 | 
							> $(@D)/.tmp_$(@F:.o=.ver);				\
 | 
				
			||||||
									\
 | 
														\
 | 
				
			||||||
		$(LD) $(LDFLAGS) -r -o $@ $(@D)/.tmp_$(@F) 		\
 | 
							$(LD) $(LDFLAGS) -r -o $@ $(@D)/.tmp_$(@F) 		\
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -42,7 +42,8 @@ static FILE *debugfile;
 | 
				
			||||||
int cur_line = 1;
 | 
					int cur_line = 1;
 | 
				
			||||||
char *cur_filename;
 | 
					char *cur_filename;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int flag_debug, flag_dump_defs, flag_dump_types, flag_warnings;
 | 
					static int flag_debug, flag_dump_defs, flag_reference, flag_dump_types,
 | 
				
			||||||
 | 
						   flag_preserve, flag_warnings;
 | 
				
			||||||
static const char *arch = "";
 | 
					static const char *arch = "";
 | 
				
			||||||
static const char *mod_prefix = "";
 | 
					static const char *mod_prefix = "";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -58,6 +59,8 @@ static const char *const symbol_type_name[] = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int equal_list(struct string_list *a, struct string_list *b);
 | 
					static int equal_list(struct string_list *a, struct string_list *b);
 | 
				
			||||||
static void print_list(FILE * f, struct string_list *list);
 | 
					static void print_list(FILE * f, struct string_list *list);
 | 
				
			||||||
 | 
					static void print_location(void);
 | 
				
			||||||
 | 
					static void print_type_name(enum symbol_type type, const char *name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*----------------------------------------------------------------------*/
 | 
					/*----------------------------------------------------------------------*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -151,27 +154,68 @@ struct symbol *find_symbol(const char *name, enum symbol_type ns)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (sym = symtab[h]; sym; sym = sym->hash_next)
 | 
						for (sym = symtab[h]; sym; sym = sym->hash_next)
 | 
				
			||||||
		if (map_to_ns(sym->type) == map_to_ns(ns) &&
 | 
							if (map_to_ns(sym->type) == map_to_ns(ns) &&
 | 
				
			||||||
		    strcmp(name, sym->name) == 0)
 | 
							    strcmp(name, sym->name) == 0 &&
 | 
				
			||||||
 | 
							    sym->is_declared)
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return sym;
 | 
						return sym;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct symbol *add_symbol(const char *name, enum symbol_type type,
 | 
					static int is_unknown_symbol(struct symbol *sym)
 | 
				
			||||||
			  struct string_list *defn, int is_extern)
 | 
					{
 | 
				
			||||||
 | 
						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);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct symbol *__add_symbol(const char *name, enum symbol_type type,
 | 
				
			||||||
 | 
								    struct string_list *defn, int is_extern,
 | 
				
			||||||
 | 
								    int is_reference)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	unsigned long h = crc32(name) % HASH_BUCKETS;
 | 
						unsigned long h = crc32(name) % HASH_BUCKETS;
 | 
				
			||||||
	struct symbol *sym;
 | 
						struct symbol *sym;
 | 
				
			||||||
 | 
						enum symbol_status status = STATUS_UNCHANGED;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (sym = symtab[h]; sym; sym = sym->hash_next) {
 | 
						for (sym = symtab[h]; sym; sym = sym->hash_next) {
 | 
				
			||||||
		if (map_to_ns(sym->type) == map_to_ns(type)
 | 
							if (map_to_ns(sym->type) == map_to_ns(type) &&
 | 
				
			||||||
		    && strcmp(name, sym->name) == 0) {
 | 
							    strcmp(name, sym->name) == 0) {
 | 
				
			||||||
			if (!equal_list(sym->defn, defn))
 | 
								if (is_reference)
 | 
				
			||||||
 | 
									/* fall through */ ;
 | 
				
			||||||
 | 
								else if (sym->type == type &&
 | 
				
			||||||
 | 
									 equal_list(sym->defn, defn)) {
 | 
				
			||||||
 | 
									sym->is_declared = 1;
 | 
				
			||||||
 | 
									return sym;
 | 
				
			||||||
 | 
								} else if (!sym->is_declared) {
 | 
				
			||||||
 | 
									status = is_unknown_symbol(sym) ?
 | 
				
			||||||
 | 
										STATUS_DEFINED : STATUS_MODIFIED;
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
				error_with_pos("redefinition of %s", name);
 | 
									error_with_pos("redefinition of %s", name);
 | 
				
			||||||
			return sym;
 | 
									return sym;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (sym) {
 | 
				
			||||||
 | 
							struct symbol **psym;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (psym = &symtab[h]; *psym; psym = &(*psym)->hash_next) {
 | 
				
			||||||
 | 
								if (*psym == sym) {
 | 
				
			||||||
 | 
									*psym = sym->hash_next;
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							--nsyms;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sym = xmalloc(sizeof(*sym));
 | 
						sym = xmalloc(sizeof(*sym));
 | 
				
			||||||
	sym->name = name;
 | 
						sym->name = name;
 | 
				
			||||||
	sym->type = type;
 | 
						sym->type = type;
 | 
				
			||||||
| 
						 | 
					@ -183,6 +227,9 @@ struct symbol *add_symbol(const char *name, enum symbol_type type,
 | 
				
			||||||
	sym->hash_next = symtab[h];
 | 
						sym->hash_next = symtab[h];
 | 
				
			||||||
	symtab[h] = sym;
 | 
						symtab[h] = sym;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sym->is_declared = !is_reference;
 | 
				
			||||||
 | 
						sym->status = status;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (flag_debug) {
 | 
						if (flag_debug) {
 | 
				
			||||||
		fprintf(debugfile, "Defn for %s %s == <",
 | 
							fprintf(debugfile, "Defn for %s %s == <",
 | 
				
			||||||
			symbol_type_name[type], name);
 | 
								symbol_type_name[type], name);
 | 
				
			||||||
| 
						 | 
					@ -196,6 +243,18 @@ struct symbol *add_symbol(const char *name, enum symbol_type type,
 | 
				
			||||||
	return sym;
 | 
						return sym;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct symbol *add_reference_symbol(const char *name, enum symbol_type type,
 | 
				
			||||||
 | 
									    struct string_list *defn, int is_extern)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return __add_symbol(name, type, defn, is_extern, 1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*----------------------------------------------------------------------*/
 | 
					/*----------------------------------------------------------------------*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void free_node(struct string_list *node)
 | 
					void free_node(struct string_list *node)
 | 
				
			||||||
| 
						 | 
					@ -236,6 +295,82 @@ static int equal_list(struct string_list *a, struct string_list *b)
 | 
				
			||||||
	return !a && !b;
 | 
						return !a && !b;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct string_list *read_node(FILE *f)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char buffer[256];
 | 
				
			||||||
 | 
						struct string_list node = {
 | 
				
			||||||
 | 
							.string = buffer,
 | 
				
			||||||
 | 
							.tag = SYM_NORMAL };
 | 
				
			||||||
 | 
						int c;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while ((c = fgetc(f)) != EOF) {
 | 
				
			||||||
 | 
							if (c == ' ') {
 | 
				
			||||||
 | 
								if (node.string == buffer)
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							} 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] == '#') {
 | 
				
			||||||
 | 
							int n;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (n = 0; n < ARRAY_SIZE(symbol_type_name); n++) {
 | 
				
			||||||
 | 
								if (node.string[0] == symbol_type_name[n][0]) {
 | 
				
			||||||
 | 
									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;
 | 
				
			||||||
 | 
							int is_extern = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							sym = read_node(f);
 | 
				
			||||||
 | 
							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);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							add_reference_symbol(xstrdup(sym->string), sym->tag,
 | 
				
			||||||
 | 
										      defn, is_extern);
 | 
				
			||||||
 | 
							free_node(sym);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void print_node(FILE * f, struct string_list *list)
 | 
					static void print_node(FILE * f, struct string_list *list)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (list->tag != SYM_NORMAL) {
 | 
						if (list->tag != SYM_NORMAL) {
 | 
				
			||||||
| 
						 | 
					@ -311,6 +446,7 @@ static unsigned long expand_and_crc_sym(struct symbol *sym, unsigned long crc)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		case SYM_TYPEDEF:
 | 
							case SYM_TYPEDEF:
 | 
				
			||||||
			subsym = find_symbol(cur->string, cur->tag);
 | 
								subsym = find_symbol(cur->string, cur->tag);
 | 
				
			||||||
 | 
								/* FIXME: Bad reference files can segfault here. */
 | 
				
			||||||
			if (subsym->expansion_trail) {
 | 
								if (subsym->expansion_trail) {
 | 
				
			||||||
				if (flag_dump_defs)
 | 
									if (flag_dump_defs)
 | 
				
			||||||
					fprintf(debugfile, "%s ", cur->string);
 | 
										fprintf(debugfile, "%s ", cur->string);
 | 
				
			||||||
| 
						 | 
					@ -347,9 +483,22 @@ static unsigned long expand_and_crc_sym(struct symbol *sym, unsigned long crc)
 | 
				
			||||||
				t = n;
 | 
									t = n;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				n = xmalloc(sizeof(*n));
 | 
									n = xmalloc(sizeof(*n));
 | 
				
			||||||
				n->string = xstrdup("{ UNKNOWN }");
 | 
									n->string = xstrdup("{");
 | 
				
			||||||
				n->tag = SYM_NORMAL;
 | 
									n->tag = SYM_NORMAL;
 | 
				
			||||||
				n->next = t;
 | 
									n->next = t;
 | 
				
			||||||
 | 
									t = n;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									n = xmalloc(sizeof(*n));
 | 
				
			||||||
 | 
									n->string = xstrdup("UNKNOWN");
 | 
				
			||||||
 | 
									n->tag = SYM_NORMAL;
 | 
				
			||||||
 | 
									n->next = t;
 | 
				
			||||||
 | 
									t = n;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									n = xmalloc(sizeof(*n));
 | 
				
			||||||
 | 
									n->string = xstrdup("}");
 | 
				
			||||||
 | 
									n->tag = SYM_NORMAL;
 | 
				
			||||||
 | 
									n->next = t;
 | 
				
			||||||
 | 
									t = n;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				subsym =
 | 
									subsym =
 | 
				
			||||||
				    add_symbol(cur->string, cur->tag, n, 0);
 | 
									    add_symbol(cur->string, cur->tag, n, 0);
 | 
				
			||||||
| 
						 | 
					@ -397,20 +546,42 @@ void export_symbol(const char *name)
 | 
				
			||||||
		error_with_pos("export undefined symbol %s", name);
 | 
							error_with_pos("export undefined symbol %s", name);
 | 
				
			||||||
	else {
 | 
						else {
 | 
				
			||||||
		unsigned long crc;
 | 
							unsigned long crc;
 | 
				
			||||||
 | 
							int has_changed = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (flag_dump_defs)
 | 
							if (flag_dump_defs)
 | 
				
			||||||
			fprintf(debugfile, "Export %s == <", name);
 | 
								fprintf(debugfile, "Export %s == <", name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		expansion_trail = (struct symbol *)-1L;
 | 
							expansion_trail = (struct symbol *)-1L;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							sym->expansion_trail = expansion_trail;
 | 
				
			||||||
 | 
							expansion_trail = sym;
 | 
				
			||||||
		crc = expand_and_crc_sym(sym, 0xffffffff) ^ 0xffffffff;
 | 
							crc = expand_and_crc_sym(sym, 0xffffffff) ^ 0xffffffff;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		sym = expansion_trail;
 | 
							sym = expansion_trail;
 | 
				
			||||||
		while (sym != (struct symbol *)-1L) {
 | 
							while (sym != (struct symbol *)-1L) {
 | 
				
			||||||
			struct symbol *n = sym->expansion_trail;
 | 
								struct symbol *n = sym->expansion_trail;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								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++;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			sym->expansion_trail = 0;
 | 
								sym->expansion_trail = 0;
 | 
				
			||||||
			sym = n;
 | 
								sym = n;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							if (has_changed)
 | 
				
			||||||
 | 
								fprintf(stderr, "\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (flag_dump_defs)
 | 
							if (flag_dump_defs)
 | 
				
			||||||
			fputs(">\n", debugfile);
 | 
								fputs(">\n", debugfile);
 | 
				
			||||||
| 
						 | 
					@ -421,13 +592,26 @@ void export_symbol(const char *name)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*----------------------------------------------------------------------*/
 | 
					/*----------------------------------------------------------------------*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (type != SYM_NORMAL)
 | 
				
			||||||
 | 
							fprintf(stderr, "%s %s", symbol_type_name[type], name);
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							fprintf(stderr, "%s", name);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void error_with_pos(const char *fmt, ...)
 | 
					void error_with_pos(const char *fmt, ...)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	va_list args;
 | 
						va_list args;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (flag_warnings) {
 | 
						if (flag_warnings) {
 | 
				
			||||||
		fprintf(stderr, "%s:%d: ", cur_filename ? : "<stdin>",
 | 
							print_location();
 | 
				
			||||||
			cur_line);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		va_start(args, fmt);
 | 
							va_start(args, fmt);
 | 
				
			||||||
		vfprintf(stderr, fmt, args);
 | 
							vfprintf(stderr, fmt, args);
 | 
				
			||||||
| 
						 | 
					@ -445,7 +629,9 @@ static void genksyms_usage(void)
 | 
				
			||||||
	      "  -a, --arch            Select architecture\n"
 | 
						      "  -a, --arch            Select architecture\n"
 | 
				
			||||||
	      "  -d, --debug           Increment the debug level (repeatable)\n"
 | 
						      "  -d, --debug           Increment the debug level (repeatable)\n"
 | 
				
			||||||
	      "  -D, --dump            Dump expanded symbol defs (for debugging only)\n"
 | 
						      "  -D, --dump            Dump expanded symbol defs (for debugging only)\n"
 | 
				
			||||||
	      "  -T, --dump-types file Dump expanded types into file (for debugging only)\n"
 | 
						      "  -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"
 | 
				
			||||||
	      "  -w, --warnings        Enable warnings\n"
 | 
						      "  -w, --warnings        Enable warnings\n"
 | 
				
			||||||
	      "  -q, --quiet           Disable warnings (default)\n"
 | 
						      "  -q, --quiet           Disable warnings (default)\n"
 | 
				
			||||||
	      "  -h, --help            Print this message\n"
 | 
						      "  -h, --help            Print this message\n"
 | 
				
			||||||
| 
						 | 
					@ -454,7 +640,9 @@ static void genksyms_usage(void)
 | 
				
			||||||
	      "  -a                    Select architecture\n"
 | 
						      "  -a                    Select architecture\n"
 | 
				
			||||||
	      "  -d                    Increment the debug level (repeatable)\n"
 | 
						      "  -d                    Increment the debug level (repeatable)\n"
 | 
				
			||||||
	      "  -D                    Dump expanded symbol defs (for debugging only)\n"
 | 
						      "  -D                    Dump expanded symbol defs (for debugging only)\n"
 | 
				
			||||||
	      "  -T file               Dump expanded types into file (for debugging only)\n"
 | 
						      "  -r file               Read reference symbols from a file\n"
 | 
				
			||||||
 | 
						      "  -T file               Dump expanded types into file\n"
 | 
				
			||||||
 | 
						      "  -p                    Preserve reference modversions or fail\n"
 | 
				
			||||||
	      "  -w                    Enable warnings\n"
 | 
						      "  -w                    Enable warnings\n"
 | 
				
			||||||
	      "  -q                    Disable warnings (default)\n"
 | 
						      "  -q                    Disable warnings (default)\n"
 | 
				
			||||||
	      "  -h                    Print this message\n"
 | 
						      "  -h                    Print this message\n"
 | 
				
			||||||
| 
						 | 
					@ -465,7 +653,7 @@ static void genksyms_usage(void)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int main(int argc, char **argv)
 | 
					int main(int argc, char **argv)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	FILE *dumpfile = NULL;
 | 
						FILE *dumpfile = NULL, *ref_file = NULL;
 | 
				
			||||||
	int o;
 | 
						int o;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef __GNU_LIBRARY__
 | 
					#ifdef __GNU_LIBRARY__
 | 
				
			||||||
| 
						 | 
					@ -475,16 +663,18 @@ int main(int argc, char **argv)
 | 
				
			||||||
		{"warnings", 0, 0, 'w'},
 | 
							{"warnings", 0, 0, 'w'},
 | 
				
			||||||
		{"quiet", 0, 0, 'q'},
 | 
							{"quiet", 0, 0, 'q'},
 | 
				
			||||||
		{"dump", 0, 0, 'D'},
 | 
							{"dump", 0, 0, 'D'},
 | 
				
			||||||
 | 
							{"reference", 1, 0, 'r'},
 | 
				
			||||||
		{"dump-types", 1, 0, 'T'},
 | 
							{"dump-types", 1, 0, 'T'},
 | 
				
			||||||
 | 
							{"preserve", 0, 0, 'p'},
 | 
				
			||||||
		{"version", 0, 0, 'V'},
 | 
							{"version", 0, 0, 'V'},
 | 
				
			||||||
		{"help", 0, 0, 'h'},
 | 
							{"help", 0, 0, 'h'},
 | 
				
			||||||
		{0, 0, 0, 0}
 | 
							{0, 0, 0, 0}
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	while ((o = getopt_long(argc, argv, "a:dwqVDT:h",
 | 
						while ((o = getopt_long(argc, argv, "a:dwqVDr:T:ph",
 | 
				
			||||||
				&long_opts[0], NULL)) != EOF)
 | 
									&long_opts[0], NULL)) != EOF)
 | 
				
			||||||
#else				/* __GNU_LIBRARY__ */
 | 
					#else				/* __GNU_LIBRARY__ */
 | 
				
			||||||
	while ((o = getopt(argc, argv, "a:dwqVDT:h")) != EOF)
 | 
						while ((o = getopt(argc, argv, "a:dwqVDr:T:ph")) != EOF)
 | 
				
			||||||
#endif				/* __GNU_LIBRARY__ */
 | 
					#endif				/* __GNU_LIBRARY__ */
 | 
				
			||||||
		switch (o) {
 | 
							switch (o) {
 | 
				
			||||||
		case 'a':
 | 
							case 'a':
 | 
				
			||||||
| 
						 | 
					@ -505,6 +695,14 @@ int main(int argc, char **argv)
 | 
				
			||||||
		case 'D':
 | 
							case 'D':
 | 
				
			||||||
			flag_dump_defs = 1;
 | 
								flag_dump_defs = 1;
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
 | 
							case 'r':
 | 
				
			||||||
 | 
								flag_reference = 1;
 | 
				
			||||||
 | 
								ref_file = fopen(optarg, "r");
 | 
				
			||||||
 | 
								if (!ref_file) {
 | 
				
			||||||
 | 
									perror(optarg);
 | 
				
			||||||
 | 
									return 1;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
		case 'T':
 | 
							case 'T':
 | 
				
			||||||
			flag_dump_types = 1;
 | 
								flag_dump_types = 1;
 | 
				
			||||||
			dumpfile = fopen(optarg, "w");
 | 
								dumpfile = fopen(optarg, "w");
 | 
				
			||||||
| 
						 | 
					@ -513,6 +711,9 @@ int main(int argc, char **argv)
 | 
				
			||||||
				return 1;
 | 
									return 1;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
 | 
							case 'p':
 | 
				
			||||||
 | 
								flag_preserve = 1;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
		case 'h':
 | 
							case 'h':
 | 
				
			||||||
			genksyms_usage();
 | 
								genksyms_usage();
 | 
				
			||||||
			return 0;
 | 
								return 0;
 | 
				
			||||||
| 
						 | 
					@ -533,6 +734,9 @@ int main(int argc, char **argv)
 | 
				
			||||||
		/* setlinebuf(debugfile); */
 | 
							/* setlinebuf(debugfile); */
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (flag_reference)
 | 
				
			||||||
 | 
							read_reference(ref_file);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	yyparse();
 | 
						yyparse();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (flag_dump_types && visited_symbols) {
 | 
						if (flag_dump_types && visited_symbols) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -29,6 +29,10 @@ enum symbol_type {
 | 
				
			||||||
	SYM_NORMAL, SYM_TYPEDEF, SYM_ENUM, SYM_STRUCT, SYM_UNION
 | 
						SYM_NORMAL, SYM_TYPEDEF, SYM_ENUM, SYM_STRUCT, SYM_UNION
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum symbol_status {
 | 
				
			||||||
 | 
						STATUS_UNCHANGED, STATUS_DEFINED, STATUS_MODIFIED
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct string_list {
 | 
					struct string_list {
 | 
				
			||||||
	struct string_list *next;
 | 
						struct string_list *next;
 | 
				
			||||||
	enum symbol_type tag;
 | 
						enum symbol_type tag;
 | 
				
			||||||
| 
						 | 
					@ -43,6 +47,8 @@ struct symbol {
 | 
				
			||||||
	struct symbol *expansion_trail;
 | 
						struct symbol *expansion_trail;
 | 
				
			||||||
	struct symbol *visited;
 | 
						struct symbol *visited;
 | 
				
			||||||
	int is_extern;
 | 
						int is_extern;
 | 
				
			||||||
 | 
						int is_declared;
 | 
				
			||||||
 | 
						enum symbol_status status;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct string_list **yystype;
 | 
					typedef struct string_list **yystype;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue