⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 module.c

📁 linux 2.6.19 kernel source code before patching
💻 C
📖 第 1 页 / 共 5 页
字号:
	mod = load_module(umod, len, uargs);	if (IS_ERR(mod)) {		mutex_unlock(&module_mutex);		return PTR_ERR(mod);	}	/* Now sew it into the lists.  They won't access us, since           strong_try_module_get() will fail. */	stop_machine_run(__link_module, mod, NR_CPUS);	/* Drop lock so they can recurse */	mutex_unlock(&module_mutex);	blocking_notifier_call_chain(&module_notify_list,			MODULE_STATE_COMING, mod);	/* Start the module */	if (mod->init != NULL)		ret = mod->init();	if (ret < 0) {		/* Init routine failed: abort.  Try to protect us from                   buggy refcounters. */		mod->state = MODULE_STATE_GOING;		synchronize_sched();		if (mod->unsafe)			printk(KERN_ERR "%s: module is now stuck!\n",			       mod->name);		else {			module_put(mod);			mutex_lock(&module_mutex);			free_module(mod);			mutex_unlock(&module_mutex);		}		return ret;	}	/* Now it's a first class citizen! */	mutex_lock(&module_mutex);	mod->state = MODULE_STATE_LIVE;	/* Drop initial reference. */	module_put(mod);	unwind_remove_table(mod->unwind_info, 1);	module_free(mod, mod->module_init);	mod->module_init = NULL;	mod->init_size = 0;	mod->init_text_size = 0;	mutex_unlock(&module_mutex);	return 0;}static inline int within(unsigned long addr, void *start, unsigned long size){	return ((void *)addr >= start && (void *)addr < start + size);}#ifdef CONFIG_KALLSYMS/* * This ignores the intensely annoying "mapping symbols" found * in ARM ELF files: $a, $t and $d. */static inline int is_arm_mapping_symbol(const char *str){	return str[0] == '$' && strchr("atd", str[1]) 	       && (str[2] == '\0' || str[2] == '.');}static const char *get_ksymbol(struct module *mod,			       unsigned long addr,			       unsigned long *size,			       unsigned long *offset){	unsigned int i, best = 0;	unsigned long nextval;	/* At worse, next value is at end of module */	if (within(addr, mod->module_init, mod->init_size))		nextval = (unsigned long)mod->module_init+mod->init_text_size;	else 		nextval = (unsigned long)mod->module_core+mod->core_text_size;	/* Scan for closest preceeding symbol, and next symbol. (ELF           starts real symbols at 1). */	for (i = 1; i < mod->num_symtab; i++) {		if (mod->symtab[i].st_shndx == SHN_UNDEF)			continue;		/* We ignore unnamed symbols: they're uninformative		 * and inserted at a whim. */		if (mod->symtab[i].st_value <= addr		    && mod->symtab[i].st_value > mod->symtab[best].st_value		    && *(mod->strtab + mod->symtab[i].st_name) != '\0'		    && !is_arm_mapping_symbol(mod->strtab + mod->symtab[i].st_name))			best = i;		if (mod->symtab[i].st_value > addr		    && mod->symtab[i].st_value < nextval		    && *(mod->strtab + mod->symtab[i].st_name) != '\0'		    && !is_arm_mapping_symbol(mod->strtab + mod->symtab[i].st_name))			nextval = mod->symtab[i].st_value;	}	if (!best)		return NULL;	if (size)		*size = nextval - mod->symtab[best].st_value;	if (offset)		*offset = addr - mod->symtab[best].st_value;	return mod->strtab + mod->symtab[best].st_name;}/* For kallsyms to ask for address resolution.  NULL means not found.   We don't lock, as this is used for oops resolution and races are a   lesser concern. */const char *module_address_lookup(unsigned long addr,				  unsigned long *size,				  unsigned long *offset,				  char **modname){	struct module *mod;	list_for_each_entry(mod, &modules, list) {		if (within(addr, mod->module_init, mod->init_size)		    || within(addr, mod->module_core, mod->core_size)) {			if (modname)				*modname = mod->name;			return get_ksymbol(mod, addr, size, offset);		}	}	return NULL;}int lookup_module_symbol_name(unsigned long addr, char *symname){	struct module *mod;	mutex_lock(&module_mutex);	list_for_each_entry(mod, &modules, list) {		if (within(addr, mod->module_init, mod->init_size) ||		    within(addr, mod->module_core, mod->core_size)) {			const char *sym;			sym = get_ksymbol(mod, addr, NULL, NULL);			if (!sym)				goto out;			strlcpy(symname, sym, KSYM_NAME_LEN + 1);			mutex_unlock(&module_mutex);			return 0;		}	}out:	mutex_unlock(&module_mutex);	return -ERANGE;}int lookup_module_symbol_attrs(unsigned long addr, unsigned long *size,			unsigned long *offset, char *modname, char *name){	struct module *mod;	mutex_lock(&module_mutex);	list_for_each_entry(mod, &modules, list) {		if (within(addr, mod->module_init, mod->init_size) ||		    within(addr, mod->module_core, mod->core_size)) {			const char *sym;			sym = get_ksymbol(mod, addr, size, offset);			if (!sym)				goto out;			if (modname)				strlcpy(modname, mod->name, MODULE_NAME_LEN + 1);			if (name)				strlcpy(name, sym, KSYM_NAME_LEN + 1);			mutex_unlock(&module_mutex);			return 0;		}	}out:	mutex_unlock(&module_mutex);	return -ERANGE;}int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type,			char *name, char *module_name, int *exported){	struct module *mod;	mutex_lock(&module_mutex);	list_for_each_entry(mod, &modules, list) {		if (symnum < mod->num_symtab) {			*value = mod->symtab[symnum].st_value;			*type = mod->symtab[symnum].st_info;			strlcpy(name, mod->strtab + mod->symtab[symnum].st_name,				KSYM_NAME_LEN + 1);			strlcpy(module_name, mod->name, MODULE_NAME_LEN + 1);			*exported = is_exported(name, mod);			mutex_unlock(&module_mutex);			return 0;		}		symnum -= mod->num_symtab;	}	mutex_unlock(&module_mutex);	return -ERANGE;}static unsigned long mod_find_symname(struct module *mod, const char *name){	unsigned int i;	for (i = 0; i < mod->num_symtab; i++)		if (strcmp(name, mod->strtab+mod->symtab[i].st_name) == 0 &&		    mod->symtab[i].st_info != 'U')			return mod->symtab[i].st_value;	return 0;}/* Look for this name: can be of form module:name. */unsigned long module_kallsyms_lookup_name(const char *name){	struct module *mod;	char *colon;	unsigned long ret = 0;	/* Don't lock: we're in enough trouble already. */	if ((colon = strchr(name, ':')) != NULL) {		*colon = '\0';		if ((mod = find_module(name)) != NULL)			ret = mod_find_symname(mod, colon+1);		*colon = ':';	} else {		list_for_each_entry(mod, &modules, list)			if ((ret = mod_find_symname(mod, name)) != 0)				break;	}	return ret;}#endif /* CONFIG_KALLSYMS *//* Called by the /proc file system to return a list of modules. */static void *m_start(struct seq_file *m, loff_t *pos){	struct list_head *i;	loff_t n = 0;	mutex_lock(&module_mutex);	list_for_each(i, &modules) {		if (n++ == *pos)			break;	}	if (i == &modules)		return NULL;	return i;}static void *m_next(struct seq_file *m, void *p, loff_t *pos){	struct list_head *i = p;	(*pos)++;	if (i->next == &modules)		return NULL;	return i->next;}static void m_stop(struct seq_file *m, void *p){	mutex_unlock(&module_mutex);}static char *taint_flags(unsigned int taints, char *buf){	int bx = 0;	if (taints) {		buf[bx++] = '(';		if (taints & TAINT_PROPRIETARY_MODULE)			buf[bx++] = 'P';		if (taints & TAINT_FORCED_MODULE)			buf[bx++] = 'F';		/*		 * TAINT_FORCED_RMMOD: could be added.		 * TAINT_UNSAFE_SMP, TAINT_MACHINE_CHECK, TAINT_BAD_PAGE don't		 * apply to modules.		 */		buf[bx++] = ')';	}	buf[bx] = '\0';	return buf;}static int m_show(struct seq_file *m, void *p){	struct module *mod = list_entry(p, struct module, list);	char buf[8];	seq_printf(m, "%s %lu",		   mod->name, mod->init_size + mod->core_size);	print_unload_info(m, mod);	/* Informative for users. */	seq_printf(m, " %s",		   mod->state == MODULE_STATE_GOING ? "Unloading":		   mod->state == MODULE_STATE_COMING ? "Loading":		   "Live");	/* Used by oprofile and other similar tools. */	seq_printf(m, " 0x%p", mod->module_core);	/* Taints info */	if (mod->taints)		seq_printf(m, " %s", taint_flags(mod->taints, buf));	seq_printf(m, "\n");	return 0;}/* Format: modulename size refcount deps address   Where refcount is a number or -, and deps is a comma-separated list   of depends or -.*/const struct seq_operations modules_op = {	.start	= m_start,	.next	= m_next,	.stop	= m_stop,	.show	= m_show};/* Given an address, look for it in the module exception tables. */const struct exception_table_entry *search_module_extables(unsigned long addr){	unsigned long flags;	const struct exception_table_entry *e = NULL;	struct module *mod;	spin_lock_irqsave(&modlist_lock, flags);	list_for_each_entry(mod, &modules, list) {		if (mod->num_exentries == 0)			continue;						e = search_extable(mod->extable,				   mod->extable + mod->num_exentries - 1,				   addr);		if (e)			break;	}	spin_unlock_irqrestore(&modlist_lock, flags);	/* Now, if we found one, we are running inside it now, hence           we cannot unload the module, hence no refcnt needed. */	return e;}/* * Is this a valid module address? */int is_module_address(unsigned long addr){	unsigned long flags;	struct module *mod;	spin_lock_irqsave(&modlist_lock, flags);	list_for_each_entry(mod, &modules, list) {		if (within(addr, mod->module_core, mod->core_size)) {			spin_unlock_irqrestore(&modlist_lock, flags);			return 1;		}	}	spin_unlock_irqrestore(&modlist_lock, flags);	return 0;}/* Is this a valid kernel address?  We don't grab the lock: we are oopsing. */struct module *__module_text_address(unsigned long addr){	struct module *mod;	list_for_each_entry(mod, &modules, list)		if (within(addr, mod->module_init, mod->init_text_size)		    || within(addr, mod->module_core, mod->core_text_size))			return mod;	return NULL;}struct module *module_text_address(unsigned long addr){	struct module *mod;	unsigned long flags;	spin_lock_irqsave(&modlist_lock, flags);	mod = __module_text_address(addr);	spin_unlock_irqrestore(&modlist_lock, flags);	return mod;}/* Don't grab lock, we're oopsing. */void print_modules(void){	struct module *mod;	char buf[8];	printk("Modules linked in:");	list_for_each_entry(mod, &modules, list)		printk(" %s%s", mod->name, taint_flags(mod->taints, buf));	printk("\n");}#ifdef CONFIG_SYSFSstatic char *make_driver_name(struct device_driver *drv){	char *driver_name;	driver_name = kmalloc(strlen(drv->name) + strlen(drv->bus->name) + 2,			      GFP_KERNEL);	if (!driver_name)		return NULL;	sprintf(driver_name, "%s:%s", drv->bus->name, drv->name);	return driver_name;}static void module_create_drivers_dir(struct module_kobject *mk){	if (!mk || mk->drivers_dir)		return;	mk->drivers_dir = kobject_add_dir(&mk->kobj, "drivers");}void module_add_driver(struct module *mod, struct device_driver *drv){	char *driver_name;	int no_warn;	struct module_kobject *mk = NULL;	if (!drv)		return;	if (mod)		mk = &mod->mkobj;	else if (drv->mod_name) {		struct kobject *mkobj;		/* Lookup built-in module entry in /sys/modules */		mkobj = kset_find_obj(&module_subsys, drv->mod_name);		if (mkobj) {			mk = container_of(mkobj, struct module_kobject, kobj);			/* remember our module structure */			drv->mkobj = mk;			/* kset_find_obj took a reference */			kobject_put(mkobj);		}	}	if (!mk)		return;	/* Don't check return codes; these calls are idempotent */	no_warn = sysfs_create_link(&drv->kobj, &mk->kobj, "module");	driver_name = make_driver_name(drv);	if (driver_name) {		module_create_drivers_dir(mk);		no_warn = sysfs_create_link(mk->drivers_dir, &drv->kobj,					    driver_name);		kfree(driver_name);	}}EXPORT_SYMBOL(module_add_driver);void module_remove_driver(struct device_driver *drv){	struct module_kobject *mk = NULL;	char *driver_name;	if (!drv)		return;	sysfs_remove_link(&drv->kobj, "module");	if (drv->owner)		mk = &drv->owner->mkobj;	else if (drv->mkobj)		mk = drv->mkobj;	if (mk && mk->drivers_dir) {		driver_name = make_driver_name(drv);		if (driver_name) {			sysfs_remove_link(mk->drivers_dir, driver_name);			kfree(driver_name);		}	}}EXPORT_SYMBOL(module_r

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -