mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	kbuild: improved modversioning support for external modules
With following patch a second option is enabled to obtain symbol information from a second external module when a external module is build. The recommended approach is to use a common kbuild file but that may be impractical in certain cases. With this patch one can copy over a Module.symvers from one external module to make symbols (and symbol versions) available for another external module. Updated documentation in Documentation/kbuild/modules.txt Signed-off-by: Sam Ravnborg <sam@ravnborg.org>
This commit is contained in:
		
							parent
							
								
									5c3ead8c72
								
							
						
					
					
						commit
						040fcc819a
					
				
					 3 changed files with 158 additions and 59 deletions
				
			
		| 
						 | 
					@ -23,7 +23,10 @@ In this document you will find information about:
 | 
				
			||||||
	=== 6. Module installation
 | 
						=== 6. Module installation
 | 
				
			||||||
	   --- 6.1 INSTALL_MOD_PATH
 | 
						   --- 6.1 INSTALL_MOD_PATH
 | 
				
			||||||
	   --- 6.2 INSTALL_MOD_DIR
 | 
						   --- 6.2 INSTALL_MOD_DIR
 | 
				
			||||||
	=== 7. Module versioning
 | 
						=== 7. Module versioning & Module.symvers
 | 
				
			||||||
 | 
						   --- 7.1 Symbols fron the kernel (vmlinux + modules)
 | 
				
			||||||
 | 
						   --- 7.2 Symbols and external modules
 | 
				
			||||||
 | 
						   --- 7.3 Symbols from another external module
 | 
				
			||||||
	=== 8. Tips & Tricks
 | 
						=== 8. Tips & Tricks
 | 
				
			||||||
	   --- 8.1 Testing for CONFIG_FOO_BAR
 | 
						   --- 8.1 Testing for CONFIG_FOO_BAR
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -89,7 +92,8 @@ when building an external module.
 | 
				
			||||||
	make -C $KDIR M=$PWD modules_install
 | 
						make -C $KDIR M=$PWD modules_install
 | 
				
			||||||
		Install the external module(s).
 | 
							Install the external module(s).
 | 
				
			||||||
		Installation default is in /lib/modules/<kernel-version>/extra,
 | 
							Installation default is in /lib/modules/<kernel-version>/extra,
 | 
				
			||||||
		but may be prefixed with INSTALL_MOD_PATH - see separate chapter.
 | 
							but may be prefixed with INSTALL_MOD_PATH - see separate
 | 
				
			||||||
 | 
							chapter.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	make -C $KDIR M=$PWD clean
 | 
						make -C $KDIR M=$PWD clean
 | 
				
			||||||
		Remove all generated files for the module - the kernel
 | 
							Remove all generated files for the module - the kernel
 | 
				
			||||||
| 
						 | 
					@ -433,7 +437,7 @@ External modules are installed in the directory:
 | 
				
			||||||
		=> Install dir: /lib/modules/$(KERNELRELEASE)/gandalf
 | 
							=> Install dir: /lib/modules/$(KERNELRELEASE)/gandalf
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
=== 7. Module versioning
 | 
					=== 7. Module versioning & Module.symvers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Module versioning is enabled by the CONFIG_MODVERSIONS tag.
 | 
					Module versioning is enabled by the CONFIG_MODVERSIONS tag.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -443,10 +447,79 @@ when a module is loaded/used then the CRC values contained in the kernel are
 | 
				
			||||||
compared with similar values in the module. If they are not equal then the
 | 
					compared with similar values in the module. If they are not equal then the
 | 
				
			||||||
kernel refuses to load the module.
 | 
					kernel refuses to load the module.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
During a kernel build a file named Module.symvers will be generated. This
 | 
					Module.symvers contains a list of all exported symbols from a kernel build.
 | 
				
			||||||
file includes the symbol version of all symbols within the kernel. If the 
 | 
					
 | 
				
			||||||
Module.symvers file is saved from the last full kernel compile one does not
 | 
					--- 7.1 Symbols fron the kernel (vmlinux + modules)
 | 
				
			||||||
have to do a full kernel compile to build a module version's compatible module.
 | 
					
 | 
				
			||||||
 | 
						During a kernel build a file named Module.symvers will be generated.
 | 
				
			||||||
 | 
						Module.symvers contains all exported symbols from the kernel and
 | 
				
			||||||
 | 
						compiled modules. For each symbols the corresponding CRC value
 | 
				
			||||||
 | 
						is stored too.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						The syntax of the Module.symvers file is:
 | 
				
			||||||
 | 
							<CRC>       <Symbol>           <module>
 | 
				
			||||||
 | 
						Sample:
 | 
				
			||||||
 | 
							0x2d036834  scsi_remove_host   drivers/scsi/scsi_mod
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						For a kernel build without CONFIG_MODVERSIONING enabled the crc
 | 
				
			||||||
 | 
						would read: 0x00000000
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Module.symvers serve two purposes.
 | 
				
			||||||
 | 
						1) It list all exported symbols both from vmlinux and all modules
 | 
				
			||||||
 | 
						2) It list CRC if CONFIG_MODVERSION is enabled
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					--- 7.2 Symbols and external modules
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						When building an external module the build system needs access to
 | 
				
			||||||
 | 
						the symbols from the kernel to check if all external symbols are
 | 
				
			||||||
 | 
						defined. This is done in the MODPOST step and to obtain all
 | 
				
			||||||
 | 
						symbols modpost reads Module.symvers from the kernel.
 | 
				
			||||||
 | 
						If a Module.symvers file is present in the directory where
 | 
				
			||||||
 | 
						the external module is being build this file will be read too.
 | 
				
			||||||
 | 
						During the MODPOST step a new Module.symvers file will be written
 | 
				
			||||||
 | 
						containing all exported symbols that was not defined in the kernel.
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
					--- 7.3 Symbols from another external module
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Sometimes one external module uses exported symbols from another
 | 
				
			||||||
 | 
						external module. Kbuild needs to have full knowledge on all symbols
 | 
				
			||||||
 | 
						to avoid spitting out warnings about undefined symbols.
 | 
				
			||||||
 | 
						Two solutions exist to let kbuild know all symbols of more than
 | 
				
			||||||
 | 
						one external module.
 | 
				
			||||||
 | 
						The method with a top-level kbuild file is recommended but may be
 | 
				
			||||||
 | 
						impractical in certain situations.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Use a top-level Kbuild file
 | 
				
			||||||
 | 
							If you have two modules: 'foo', 'bar' and 'foo' needs symbols
 | 
				
			||||||
 | 
							from 'bar' then one can use a common top-level kbuild file so
 | 
				
			||||||
 | 
							both modules are compiled in same build.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							Consider following directory layout:
 | 
				
			||||||
 | 
							./foo/ <= contains the foo module
 | 
				
			||||||
 | 
							./bar/ <= contains the bar module
 | 
				
			||||||
 | 
							The top-level Kbuild file would then look like:
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							#./Kbuild: (this file may also be named Makefile)
 | 
				
			||||||
 | 
								obj-y := foo/ bar/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							Executing:
 | 
				
			||||||
 | 
								make -C $KDIR M=`pwd`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							will then do the expected and compile both modules with full
 | 
				
			||||||
 | 
							knowledge on symbols from both modules.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Use an extra Module.symvers file
 | 
				
			||||||
 | 
							When an external module is build a Module.symvers file is
 | 
				
			||||||
 | 
							generated containing all exported symbols which are not
 | 
				
			||||||
 | 
							defined in the kernel.
 | 
				
			||||||
 | 
							To get access to symbols from module 'bar' one can copy the
 | 
				
			||||||
 | 
							Module.symvers file from the compilation of the 'bar' module
 | 
				
			||||||
 | 
							to the directory where the 'foo' module is build.
 | 
				
			||||||
 | 
							During the module build kbuild will read the Module.symvers
 | 
				
			||||||
 | 
							file in the directory of the external module and when the
 | 
				
			||||||
 | 
							build is finished a new Module.symvers file is created
 | 
				
			||||||
 | 
							containing the sum of all symbols defined and not part of the
 | 
				
			||||||
 | 
							kernel.
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
=== 8. Tips & Tricks
 | 
					=== 8. Tips & Tricks
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -39,7 +39,8 @@ include .config
 | 
				
			||||||
include scripts/Kbuild.include
 | 
					include scripts/Kbuild.include
 | 
				
			||||||
include scripts/Makefile.lib
 | 
					include scripts/Makefile.lib
 | 
				
			||||||
 | 
					
 | 
				
			||||||
symverfile := $(objtree)/Module.symvers
 | 
					kernelsymfile := $(objtree)/Module.symvers
 | 
				
			||||||
 | 
					modulesymfile := $(KBUILD_EXTMOD)/Modules.symvers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Step 1), find all modules listed in $(MODVERDIR)/
 | 
					# Step 1), find all modules listed in $(MODVERDIR)/
 | 
				
			||||||
__modules := $(sort $(shell grep -h '\.ko' /dev/null $(wildcard $(MODVERDIR)/*.mod)))
 | 
					__modules := $(sort $(shell grep -h '\.ko' /dev/null $(wildcard $(MODVERDIR)/*.mod)))
 | 
				
			||||||
| 
						 | 
					@ -54,7 +55,9 @@ quiet_cmd_modpost = MODPOST
 | 
				
			||||||
      cmd_modpost = scripts/mod/modpost            \
 | 
					      cmd_modpost = scripts/mod/modpost            \
 | 
				
			||||||
        $(if $(CONFIG_MODVERSIONS),-m)             \
 | 
					        $(if $(CONFIG_MODVERSIONS),-m)             \
 | 
				
			||||||
	$(if $(CONFIG_MODULE_SRCVERSION_ALL),-a,)  \
 | 
						$(if $(CONFIG_MODULE_SRCVERSION_ALL),-a,)  \
 | 
				
			||||||
	$(if $(KBUILD_EXTMOD),-i,-o) $(symverfile) \
 | 
						$(if $(KBUILD_EXTMOD),-i,-o) $(kernelsymfile) \
 | 
				
			||||||
 | 
						$(if $(KBUILD_EXTMOD),-I $(modulesymfile)) \
 | 
				
			||||||
 | 
						$(if $(KBUILD_EXTMOD),-o $(modulesymfile)) \
 | 
				
			||||||
	$(filter-out FORCE,$^)
 | 
						$(filter-out FORCE,$^)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.PHONY: __modpost
 | 
					.PHONY: __modpost
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -20,6 +20,8 @@ int modversions = 0;
 | 
				
			||||||
int have_vmlinux = 0;
 | 
					int have_vmlinux = 0;
 | 
				
			||||||
/* Is CONFIG_MODULE_SRCVERSION_ALL set? */
 | 
					/* Is CONFIG_MODULE_SRCVERSION_ALL set? */
 | 
				
			||||||
static int all_versions = 0;
 | 
					static int all_versions = 0;
 | 
				
			||||||
 | 
					/* If we are modposting external module set to 1 */
 | 
				
			||||||
 | 
					static int external_module = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void fatal(const char *fmt, ...)
 | 
					void fatal(const char *fmt, ...)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -45,6 +47,18 @@ void warn(const char *fmt, ...)
 | 
				
			||||||
	va_end(arglist);
 | 
						va_end(arglist);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int is_vmlinux(const char *modname)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						const char *myname;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ((myname = strrchr(modname, '/')))
 | 
				
			||||||
 | 
							myname++;
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							myname = modname;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return strcmp(myname, "vmlinux") == 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void *do_nofail(void *ptr, const char *expr)
 | 
					void *do_nofail(void *ptr, const char *expr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (!ptr) {
 | 
						if (!ptr) {
 | 
				
			||||||
| 
						 | 
					@ -100,6 +114,9 @@ struct symbol {
 | 
				
			||||||
	unsigned int crc;
 | 
						unsigned int crc;
 | 
				
			||||||
	int crc_valid;
 | 
						int crc_valid;
 | 
				
			||||||
	unsigned int weak:1;
 | 
						unsigned int weak:1;
 | 
				
			||||||
 | 
						unsigned int vmlinux:1;    /* 1 if symbol is defined in vmlinux */
 | 
				
			||||||
 | 
						unsigned int kernel:1;     /* 1 if symbol is from kernel
 | 
				
			||||||
 | 
									    *  (only for external modules) **/
 | 
				
			||||||
	char name[0];
 | 
						char name[0];
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -135,8 +152,7 @@ static struct symbol *alloc_symbol(const char *name, unsigned int weak,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* For the hash of exported symbols */
 | 
					/* For the hash of exported symbols */
 | 
				
			||||||
static void new_symbol(const char *name, struct module *module,
 | 
					static struct symbol *new_symbol(const char *name, struct module *module)
 | 
				
			||||||
		       unsigned int *crc)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	unsigned int hash;
 | 
						unsigned int hash;
 | 
				
			||||||
	struct symbol *new;
 | 
						struct symbol *new;
 | 
				
			||||||
| 
						 | 
					@ -144,10 +160,7 @@ static void new_symbol(const char *name, struct module *module,
 | 
				
			||||||
	hash = tdb_hash(name) % SYMBOL_HASH_SIZE;
 | 
						hash = tdb_hash(name) % SYMBOL_HASH_SIZE;
 | 
				
			||||||
	new = symbolhash[hash] = alloc_symbol(name, 0, symbolhash[hash]);
 | 
						new = symbolhash[hash] = alloc_symbol(name, 0, symbolhash[hash]);
 | 
				
			||||||
	new->module = module;
 | 
						new->module = module;
 | 
				
			||||||
	if (crc) {
 | 
						return new;
 | 
				
			||||||
		new->crc = *crc;
 | 
					 | 
				
			||||||
		new->crc_valid = 1;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct symbol *find_symbol(const char *name)
 | 
					static struct symbol *find_symbol(const char *name)
 | 
				
			||||||
| 
						 | 
					@ -169,19 +182,27 @@ static struct symbol *find_symbol(const char *name)
 | 
				
			||||||
 * Add an exported symbol - it may have already been added without a
 | 
					 * Add an exported symbol - it may have already been added without a
 | 
				
			||||||
 * CRC, in this case just update the CRC
 | 
					 * CRC, in this case just update the CRC
 | 
				
			||||||
 **/
 | 
					 **/
 | 
				
			||||||
static void add_exported_symbol(const char *name, struct module *module,
 | 
					static struct symbol *sym_add_exported(const char *name, struct module *mod)
 | 
				
			||||||
				unsigned int *crc)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct symbol *s = find_symbol(name);
 | 
						struct symbol *s = find_symbol(name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!s) {
 | 
						if (!s)
 | 
				
			||||||
		new_symbol(name, module, crc);
 | 
							s = new_symbol(name, mod);
 | 
				
			||||||
		return;
 | 
					
 | 
				
			||||||
	}
 | 
						s->vmlinux   = is_vmlinux(mod->name);
 | 
				
			||||||
	if (crc) {
 | 
						s->kernel    = 0;
 | 
				
			||||||
		s->crc = *crc;
 | 
						return s;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void sym_update_crc(const char *name, struct module *mod,
 | 
				
			||||||
 | 
								   unsigned int crc)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct symbol *s = find_symbol(name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!s)
 | 
				
			||||||
 | 
							s = new_symbol(name, mod);
 | 
				
			||||||
 | 
						s->crc = crc;
 | 
				
			||||||
	s->crc_valid = 1;
 | 
						s->crc_valid = 1;
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void *grab_file(const char *filename, unsigned long *size)
 | 
					void *grab_file(const char *filename, unsigned long *size)
 | 
				
			||||||
| 
						 | 
					@ -332,8 +353,7 @@ static void handle_modversions(struct module *mod, struct elf_info *info,
 | 
				
			||||||
		/* CRC'd symbol */
 | 
							/* CRC'd symbol */
 | 
				
			||||||
		if (memcmp(symname, CRC_PFX, strlen(CRC_PFX)) == 0) {
 | 
							if (memcmp(symname, CRC_PFX, strlen(CRC_PFX)) == 0) {
 | 
				
			||||||
			crc = (unsigned int) sym->st_value;
 | 
								crc = (unsigned int) sym->st_value;
 | 
				
			||||||
			add_exported_symbol(symname + strlen(CRC_PFX),
 | 
								sym_update_crc(symname + strlen(CRC_PFX), mod, crc);
 | 
				
			||||||
					    mod, &crc);
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case SHN_UNDEF:
 | 
						case SHN_UNDEF:
 | 
				
			||||||
| 
						 | 
					@ -377,8 +397,7 @@ static void handle_modversions(struct module *mod, struct elf_info *info,
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		/* All exported symbols */
 | 
							/* All exported symbols */
 | 
				
			||||||
		if (memcmp(symname, KSYMTAB_PFX, strlen(KSYMTAB_PFX)) == 0) {
 | 
							if (memcmp(symname, KSYMTAB_PFX, strlen(KSYMTAB_PFX)) == 0) {
 | 
				
			||||||
			add_exported_symbol(symname + strlen(KSYMTAB_PFX),
 | 
								sym_add_exported(symname + strlen(KSYMTAB_PFX), mod);
 | 
				
			||||||
					    mod, NULL);
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if (strcmp(symname, MODULE_SYMBOL_PREFIX "init_module") == 0)
 | 
							if (strcmp(symname, MODULE_SYMBOL_PREFIX "init_module") == 0)
 | 
				
			||||||
			mod->has_init = 1;
 | 
								mod->has_init = 1;
 | 
				
			||||||
| 
						 | 
					@ -388,18 +407,6 @@ static void handle_modversions(struct module *mod, struct elf_info *info,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int is_vmlinux(const char *modname)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	const char *myname;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if ((myname = strrchr(modname, '/')))
 | 
					 | 
				
			||||||
		myname++;
 | 
					 | 
				
			||||||
	else
 | 
					 | 
				
			||||||
		myname = modname;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return strcmp(myname, "vmlinux") == 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Parse tag=value strings from .modinfo section
 | 
					 * Parse tag=value strings from .modinfo section
 | 
				
			||||||
 **/
 | 
					 **/
 | 
				
			||||||
| 
						 | 
					@ -450,9 +457,7 @@ static void read_symbols(char *modname)
 | 
				
			||||||
	/* When there's no vmlinux, don't print warnings about
 | 
						/* When there's no vmlinux, don't print warnings about
 | 
				
			||||||
	 * unresolved symbols (since there'll be too many ;) */
 | 
						 * unresolved symbols (since there'll be too many ;) */
 | 
				
			||||||
	if (is_vmlinux(modname)) {
 | 
						if (is_vmlinux(modname)) {
 | 
				
			||||||
		unsigned int fake_crc = 0;
 | 
					 | 
				
			||||||
		have_vmlinux = 1;
 | 
							have_vmlinux = 1;
 | 
				
			||||||
		add_exported_symbol("struct_module", mod, &fake_crc);
 | 
					 | 
				
			||||||
		mod->skip = 1;
 | 
							mod->skip = 1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -665,7 +670,7 @@ static void write_if_changed(struct buffer *b, const char *fname)
 | 
				
			||||||
	fclose(file);
 | 
						fclose(file);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void read_dump(const char *fname)
 | 
					static void read_dump(const char *fname, unsigned int kernel)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	unsigned long size, pos = 0;
 | 
						unsigned long size, pos = 0;
 | 
				
			||||||
	void *file = grab_file(fname, &size);
 | 
						void *file = grab_file(fname, &size);
 | 
				
			||||||
| 
						 | 
					@ -679,6 +684,7 @@ static void read_dump(const char *fname)
 | 
				
			||||||
		char *symname, *modname, *d;
 | 
							char *symname, *modname, *d;
 | 
				
			||||||
		unsigned int crc;
 | 
							unsigned int crc;
 | 
				
			||||||
		struct module *mod;
 | 
							struct module *mod;
 | 
				
			||||||
 | 
							struct symbol *s;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (!(symname = strchr(line, '\t')))
 | 
							if (!(symname = strchr(line, '\t')))
 | 
				
			||||||
			goto fail;
 | 
								goto fail;
 | 
				
			||||||
| 
						 | 
					@ -699,13 +705,28 @@ static void read_dump(const char *fname)
 | 
				
			||||||
			mod = new_module(NOFAIL(strdup(modname)));
 | 
								mod = new_module(NOFAIL(strdup(modname)));
 | 
				
			||||||
			mod->skip = 1;
 | 
								mod->skip = 1;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		add_exported_symbol(symname, mod, &crc);
 | 
							s = sym_add_exported(symname, mod);
 | 
				
			||||||
 | 
							s->kernel = kernel;
 | 
				
			||||||
 | 
							sym_update_crc(symname, mod, crc);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return;
 | 
						return;
 | 
				
			||||||
fail:
 | 
					fail:
 | 
				
			||||||
	fatal("parse error in symbol dump file\n");
 | 
						fatal("parse error in symbol dump file\n");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* For normal builds always dump all symbols.
 | 
				
			||||||
 | 
					 * For external modules only dump symbols
 | 
				
			||||||
 | 
					 * that are not read from kernel Module.symvers.
 | 
				
			||||||
 | 
					 **/
 | 
				
			||||||
 | 
					static int dump_sym(struct symbol *sym)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (!external_module)
 | 
				
			||||||
 | 
							return 1;
 | 
				
			||||||
 | 
						if (sym->vmlinux || sym->kernel)
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						return 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
static void write_dump(const char *fname)
 | 
					static void write_dump(const char *fname)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct buffer buf = { };
 | 
						struct buffer buf = { };
 | 
				
			||||||
| 
						 | 
					@ -715,15 +736,10 @@ static void write_dump(const char *fname)
 | 
				
			||||||
	for (n = 0; n < SYMBOL_HASH_SIZE ; n++) {
 | 
						for (n = 0; n < SYMBOL_HASH_SIZE ; n++) {
 | 
				
			||||||
		symbol = symbolhash[n];
 | 
							symbol = symbolhash[n];
 | 
				
			||||||
		while (symbol) {
 | 
							while (symbol) {
 | 
				
			||||||
			symbol = symbol->next;
 | 
								if (dump_sym(symbol))
 | 
				
			||||||
		}
 | 
									buf_printf(&buf, "0x%08x\t%s\t%s\n",
 | 
				
			||||||
	}
 | 
										symbol->crc, symbol->name, 
 | 
				
			||||||
 | 
										symbol->module->name);
 | 
				
			||||||
	for (n = 0; n < SYMBOL_HASH_SIZE ; n++) {
 | 
					 | 
				
			||||||
		symbol = symbolhash[n];
 | 
					 | 
				
			||||||
		while (symbol) {
 | 
					 | 
				
			||||||
			buf_printf(&buf, "0x%08x\t%s\t%s\n", symbol->crc,
 | 
					 | 
				
			||||||
				symbol->name, symbol->module->name);
 | 
					 | 
				
			||||||
			symbol = symbol->next;
 | 
								symbol = symbol->next;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -735,13 +751,18 @@ int main(int argc, char **argv)
 | 
				
			||||||
	struct module *mod;
 | 
						struct module *mod;
 | 
				
			||||||
	struct buffer buf = { };
 | 
						struct buffer buf = { };
 | 
				
			||||||
	char fname[SZ];
 | 
						char fname[SZ];
 | 
				
			||||||
	char *dump_read = NULL, *dump_write = NULL;
 | 
						char *kernel_read = NULL, *module_read = NULL;
 | 
				
			||||||
 | 
						char *dump_write = NULL;
 | 
				
			||||||
	int opt;
 | 
						int opt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	while ((opt = getopt(argc, argv, "i:mo:a")) != -1) {
 | 
						while ((opt = getopt(argc, argv, "i:I:mo:a")) != -1) {
 | 
				
			||||||
		switch(opt) {
 | 
							switch(opt) {
 | 
				
			||||||
			case 'i':
 | 
								case 'i':
 | 
				
			||||||
				dump_read = optarg;
 | 
									kernel_read = optarg;
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								case 'I':
 | 
				
			||||||
 | 
									module_read = optarg;
 | 
				
			||||||
 | 
									external_module = 1;
 | 
				
			||||||
				break;
 | 
									break;
 | 
				
			||||||
			case 'm':
 | 
								case 'm':
 | 
				
			||||||
				modversions = 1;
 | 
									modversions = 1;
 | 
				
			||||||
| 
						 | 
					@ -757,8 +778,10 @@ int main(int argc, char **argv)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (dump_read)
 | 
						if (kernel_read)
 | 
				
			||||||
		read_dump(dump_read);
 | 
							read_dump(kernel_read, 1);
 | 
				
			||||||
 | 
						if (module_read)
 | 
				
			||||||
 | 
							read_dump(module_read, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	while (optind < argc) {
 | 
						while (optind < argc) {
 | 
				
			||||||
		read_symbols(argv[optind++]);
 | 
							read_symbols(argv[optind++]);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue