📄 module.c
字号:
unsigned int nloaded = 0, i, size[2]; struct module_sect_attrs *sect_attrs; struct module_sect_attr *sattr; struct attribute **gattr; /* Count loaded sections and allocate structures */ for (i = 0; i < nsect; i++) if (sechdrs[i].sh_flags & SHF_ALLOC) nloaded++; size[0] = ALIGN(sizeof(*sect_attrs) + nloaded * sizeof(sect_attrs->attrs[0]), sizeof(sect_attrs->grp.attrs[0])); size[1] = (nloaded + 1) * sizeof(sect_attrs->grp.attrs[0]); sect_attrs = kzalloc(size[0] + size[1], GFP_KERNEL); if (sect_attrs == NULL) return; /* Setup section attributes. */ sect_attrs->grp.name = "sections"; sect_attrs->grp.attrs = (void *)sect_attrs + size[0]; sect_attrs->nsections = 0; sattr = §_attrs->attrs[0]; gattr = §_attrs->grp.attrs[0]; for (i = 0; i < nsect; i++) { if (! (sechdrs[i].sh_flags & SHF_ALLOC)) continue; sattr->address = sechdrs[i].sh_addr; sattr->name = kstrdup(secstrings + sechdrs[i].sh_name, GFP_KERNEL); if (sattr->name == NULL) goto out; sect_attrs->nsections++; sattr->mattr.show = module_sect_show; sattr->mattr.store = NULL; sattr->mattr.attr.name = sattr->name; sattr->mattr.attr.owner = mod; sattr->mattr.attr.mode = S_IRUGO; *(gattr++) = &(sattr++)->mattr.attr; } *gattr = NULL; if (sysfs_create_group(&mod->mkobj.kobj, §_attrs->grp)) goto out; mod->sect_attrs = sect_attrs; return; out: free_sect_attrs(sect_attrs);}static void remove_sect_attrs(struct module *mod){ if (mod->sect_attrs) { sysfs_remove_group(&mod->mkobj.kobj, &mod->sect_attrs->grp); /* We are positive that no one is using any sect attrs * at this point. Deallocate immediately. */ free_sect_attrs(mod->sect_attrs); mod->sect_attrs = NULL; }}#elsestatic inline void add_sect_attrs(struct module *mod, unsigned int nsect, char *sectstrings, Elf_Shdr *sechdrs){}static inline void remove_sect_attrs(struct module *mod){}#endif /* CONFIG_KALLSYMS */#ifdef CONFIG_SYSFSint module_add_modinfo_attrs(struct module *mod){ struct module_attribute *attr; struct module_attribute *temp_attr; int error = 0; int i; mod->modinfo_attrs = kzalloc((sizeof(struct module_attribute) * (ARRAY_SIZE(modinfo_attrs) + 1)), GFP_KERNEL); if (!mod->modinfo_attrs) return -ENOMEM; temp_attr = mod->modinfo_attrs; for (i = 0; (attr = modinfo_attrs[i]) && !error; i++) { if (!attr->test || (attr->test && attr->test(mod))) { memcpy(temp_attr, attr, sizeof(*temp_attr)); temp_attr->attr.owner = mod; error = sysfs_create_file(&mod->mkobj.kobj,&temp_attr->attr); ++temp_attr; } } return error;}void module_remove_modinfo_attrs(struct module *mod){ struct module_attribute *attr; int i; for (i = 0; (attr = &mod->modinfo_attrs[i]); i++) { /* pick a field to test for end of list */ if (!attr->attr.name) break; sysfs_remove_file(&mod->mkobj.kobj,&attr->attr); if (attr->free) attr->free(mod); } kfree(mod->modinfo_attrs);}#endif#ifdef CONFIG_SYSFSint mod_sysfs_init(struct module *mod){ int err; if (!module_sysfs_initialized) { printk(KERN_ERR "%s: module sysfs not initialized\n", mod->name); err = -EINVAL; goto out; } memset(&mod->mkobj.kobj, 0, sizeof(mod->mkobj.kobj)); err = kobject_set_name(&mod->mkobj.kobj, "%s", mod->name); if (err) goto out; kobj_set_kset_s(&mod->mkobj, module_subsys); mod->mkobj.mod = mod; kobject_init(&mod->mkobj.kobj);out: return err;}int mod_sysfs_setup(struct module *mod, struct kernel_param *kparam, unsigned int num_params){ int err; /* delay uevent until full sysfs population */ err = kobject_add(&mod->mkobj.kobj); if (err) goto out; mod->holders_dir = kobject_add_dir(&mod->mkobj.kobj, "holders"); if (!mod->holders_dir) { err = -ENOMEM; goto out_unreg; } err = module_param_sysfs_setup(mod, kparam, num_params); if (err) goto out_unreg_holders; err = module_add_modinfo_attrs(mod); if (err) goto out_unreg_param; kobject_uevent(&mod->mkobj.kobj, KOBJ_ADD); return 0;out_unreg_param: module_param_sysfs_remove(mod);out_unreg_holders: kobject_unregister(mod->holders_dir);out_unreg: kobject_del(&mod->mkobj.kobj); kobject_put(&mod->mkobj.kobj);out: return err;}#endifstatic void mod_kobject_remove(struct module *mod){ module_remove_modinfo_attrs(mod); module_param_sysfs_remove(mod); kobject_unregister(mod->mkobj.drivers_dir); kobject_unregister(mod->holders_dir); kobject_unregister(&mod->mkobj.kobj);}/* * unlink the module with the whole machine is stopped with interrupts off * - this defends against kallsyms not taking locks */static int __unlink_module(void *_mod){ struct module *mod = _mod; list_del(&mod->list); return 0;}/* Free a module, remove from lists, etc (must hold module_mutex). */static void free_module(struct module *mod){ /* Delete from various lists */ stop_machine_run(__unlink_module, mod, NR_CPUS); remove_sect_attrs(mod); mod_kobject_remove(mod); unwind_remove_table(mod->unwind_info, 0); /* Arch-specific cleanup. */ module_arch_cleanup(mod); /* Module unload stuff */ module_unload_free(mod); /* This may be NULL, but that's OK */ module_free(mod, mod->module_init); kfree(mod->args); if (mod->percpu) percpu_modfree(mod->percpu); /* Free lock-classes: */ lockdep_free_key_range(mod->module_core, mod->core_size); /* Finally, free the core (containing the module structure) */ module_free(mod, mod->module_core);}void *__symbol_get(const char *symbol){ struct module *owner; unsigned long value, flags; const unsigned long *crc; spin_lock_irqsave(&modlist_lock, flags); value = __find_symbol(symbol, &owner, &crc, 1); if (value && !strong_try_module_get(owner)) value = 0; spin_unlock_irqrestore(&modlist_lock, flags); return (void *)value;}EXPORT_SYMBOL_GPL(__symbol_get);/* * Ensure that an exported symbol [global namespace] does not already exist * in the kernel or in some other module's exported symbol table. */static int verify_export_symbols(struct module *mod){ const char *name = NULL; unsigned long i, ret = 0; struct module *owner; const unsigned long *crc; for (i = 0; i < mod->num_syms; i++) if (__find_symbol(mod->syms[i].name, &owner, &crc, 1)) { name = mod->syms[i].name; ret = -ENOEXEC; goto dup; } for (i = 0; i < mod->num_gpl_syms; i++) if (__find_symbol(mod->gpl_syms[i].name, &owner, &crc, 1)) { name = mod->gpl_syms[i].name; ret = -ENOEXEC; goto dup; }dup: if (ret) printk(KERN_ERR "%s: exports duplicate symbol %s (owned by %s)\n", mod->name, name, module_name(owner)); return ret;}/* Change all symbols so that sh_value encodes the pointer directly. */static int simplify_symbols(Elf_Shdr *sechdrs, unsigned int symindex, const char *strtab, unsigned int versindex, unsigned int pcpuindex, struct module *mod){ Elf_Sym *sym = (void *)sechdrs[symindex].sh_addr; unsigned long secbase; unsigned int i, n = sechdrs[symindex].sh_size / sizeof(Elf_Sym); int ret = 0; for (i = 1; i < n; i++) { switch (sym[i].st_shndx) { case SHN_COMMON: /* We compiled with -fno-common. These are not supposed to happen. */ DEBUGP("Common symbol: %s\n", strtab + sym[i].st_name); printk("%s: please compile with -fno-common\n", mod->name); ret = -ENOEXEC; break; case SHN_ABS: /* Don't need to do anything */ DEBUGP("Absolute symbol: 0x%08lx\n", (long)sym[i].st_value); break; case SHN_UNDEF: sym[i].st_value = resolve_symbol(sechdrs, versindex, strtab + sym[i].st_name, mod); /* Ok if resolved. */ if (sym[i].st_value != 0) break; /* Ok if weak. */ if (ELF_ST_BIND(sym[i].st_info) == STB_WEAK) break; printk(KERN_WARNING "%s: Unknown symbol %s\n", mod->name, strtab + sym[i].st_name); ret = -ENOENT; break; default: /* Divert to percpu allocation if a percpu var. */ if (sym[i].st_shndx == pcpuindex) secbase = (unsigned long)mod->percpu; else secbase = sechdrs[sym[i].st_shndx].sh_addr; sym[i].st_value += secbase; break; } } return ret;}/* Update size with this section: return offset. */static long get_offset(unsigned long *size, Elf_Shdr *sechdr){ long ret; ret = ALIGN(*size, sechdr->sh_addralign ?: 1); *size = ret + sechdr->sh_size; return ret;}/* Lay out the SHF_ALLOC sections in a way not dissimilar to how ld might -- code, read-only data, read-write data, small data. Tally sizes, and place the offsets into sh_entsize fields: high bit means it belongs in init. */static void layout_sections(struct module *mod, const Elf_Ehdr *hdr, Elf_Shdr *sechdrs, const char *secstrings){ static unsigned long const masks[][2] = { /* NOTE: all executable code must be the first section * in this array; otherwise modify the text_size * finder in the two loops below */ { SHF_EXECINSTR | SHF_ALLOC, ARCH_SHF_SMALL }, { SHF_ALLOC, SHF_WRITE | ARCH_SHF_SMALL }, { SHF_WRITE | SHF_ALLOC, ARCH_SHF_SMALL }, { ARCH_SHF_SMALL | SHF_ALLOC, 0 } }; unsigned int m, i; for (i = 0; i < hdr->e_shnum; i++) sechdrs[i].sh_entsize = ~0UL; DEBUGP("Core section allocation order:\n"); for (m = 0; m < ARRAY_SIZE(masks); ++m) { for (i = 0; i < hdr->e_shnum; ++i) { Elf_Shdr *s = &sechdrs[i]; if ((s->sh_flags & masks[m][0]) != masks[m][0] || (s->sh_flags & masks[m][1]) || s->sh_entsize != ~0UL || strncmp(secstrings + s->sh_name, ".init", 5) == 0) continue; s->sh_entsize = get_offset(&mod->core_size, s); DEBUGP("\t%s\n", secstrings + s->sh_name); } if (m == 0) mod->core_text_size = mod->core_size; } DEBUGP("Init section allocation order:\n"); for (m = 0; m < ARRAY_SIZE(masks); ++m) { for (i = 0; i < hdr->e_shnum; ++i) { Elf_Shdr *s = &sechdrs[i]; if ((s->sh_flags & masks[m][0]) != masks[m][0] || (s->sh_flags & masks[m][1]) || s->sh_entsize != ~0UL || strncmp(secstrings + s->sh_name, ".init", 5) != 0) continue; s->sh_entsize = (get_offset(&mod->init_size, s) | INIT_OFFSET_MASK); DEBUGP("\t%s\n", secstrings + s->sh_name); } if (m == 0) mod->init_text_size = mod->init_size; }}static void set_license(struct module *mod, const char *license){ if (!license) license = "unspecified"; if (!license_is_gpl_compatible(license)) { if (!(tainted & TAINT_PROPRIETARY_MODULE)) printk(KERN_WARNING "%s: module license '%s' taints " "kernel.\n", mod->name, license); add_taint_module(mod, TAINT_PROPRIETARY_MODULE); }}/* Parse tag=value strings from .modinfo section */static char *next_string(char *string, unsigned long *secsize){ /* Skip non-zero chars */ while (string[0]) { string++; if ((*secsize)-- <= 1) return NULL; } /* Skip any zero padding. */ while (!string[0]) { string++; if ((*secsize)-- <= 1) return NULL; } return string;}static char *get_modinfo(Elf_Shdr *sechdrs, unsigned int info, const char *tag){ char *p; unsigned int taglen = strlen(tag); unsigned long size = sechdrs[info].sh_size; for (p = (char *)sechdrs[info].sh_addr; p; p = next_string(p, &size)) { if (strncmp(p, tag, taglen) == 0 && p[taglen] == '=') return p + taglen + 1; } return NULL;}static void setup_modinfo(struct module *mod, Elf_Shdr *sechdrs, unsigned int infoindex){ struct module_attribute *attr; int i; for (i = 0; (attr = modinfo_attrs[i]); i++) { if (attr->setup) attr->setup(mod, get_modinfo(sechdrs, infoindex, attr->attr.name)); }}#ifdef CONFIG_KALLSYMSstatic int is_exported(const char *name, const struct module *mod){ if (!mod && lookup_symbol(name, __start___ksymtab, __stop___ksymtab)) return 1; else if (mod && lookup_symbol(name, mod->syms, mod->syms + mod->num_syms)) return 1; else return 0;}/* As per nm */static char elf_type(const Elf_Sym *sym, Elf_Shdr *sechdrs, const char *secstrings, struct module *mod){ if (ELF_ST_BIND(sym->st_info) == STB_WEAK) { if (ELF_ST_TYPE(sym->st_info) == STT_OBJECT) return 'v'; else return 'w'; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -