📄 insmod.c
字号:
str = alloca(r - q + 1); memcpy(str, q, r - q); /* I don't know if it is usefull, as the previous case doesn't null terminate the string ??? */ str[r - q] = '\0'; /* Keep next fields */ q = r; } else { /* last string */ str = q; q = ""; } } if (*p == 's') { /* Normal string */ obj_string_patch(f, sym->secidx, loc - contents, str); loc += tgt_sizeof_char_p; } else { /* Array of chars (in fact, matrix !) */ unsigned long charssize; /* size of each member */ /* Get the size of each member */ /* Probably we should do that outside the loop ? */ if (!isdigit(*(p + 1))) { error_msg("parameter type 'c' for %s must be followed by" " the maximum size", key); return 0; } charssize = strtoul(p + 1, (char **) NULL, 10); /* Check length */ if (strlen(str) >= charssize) { error_msg("string too long for %s (max %ld)", key, charssize - 1); return 0; } /* Copy to location */ strcpy((char *) loc, str); loc += charssize; } } else { long v = strtoul(q, &q, 0); switch (*p) { case 'b': *loc++ = v; break; case 'h': *(short *) loc = v; loc += tgt_sizeof_short; break; case 'i': *(int *) loc = v; loc += tgt_sizeof_int; break; case 'l': *(long *) loc = v; loc += tgt_sizeof_long; break; default: error_msg("unknown parameter type '%c' for %s", *p, key); return 0; } } retry_end_of_value: switch (*q) { case '\0': goto end_of_arg; case ' ': case '\t': case '\n': case '\r': ++q; goto retry_end_of_value; case ',': if (++n > max) { error_msg("too many values for %s (max %d)", key, max); return 0; } ++q; break; default: error_msg("invalid argument syntax for %s", key); return 0; } } end_of_arg: if (n < min) { error_msg("too few values for %s (min %d)", key, min); return 0; } argc--, argv++; } return 1;}#ifdef BB_FEATURE_INSMOD_VERSION_CHECKINGstatic int new_is_module_checksummed(struct obj_file *f){ const char *p = get_modinfo_value(f, "using_checksums"); if (p) return atoi(p); else return 0;}/* Get the module's kernel version in the canonical integer form. */static intnew_get_module_version(struct obj_file *f, char str[STRVERSIONLEN]){ char *p, *q; int a, b, c; p = get_modinfo_value(f, "kernel_version"); if (p == NULL) return -1; strncpy(str, p, STRVERSIONLEN); a = strtoul(p, &p, 10); if (*p != '.') return -1; b = strtoul(p + 1, &p, 10); if (*p != '.') return -1; c = strtoul(p + 1, &q, 10); if (p + 1 == q) return -1; return a << 16 | b << 8 | c;}#endif /* BB_FEATURE_INSMOD_VERSION_CHECKING */#ifdef BB_FEATURE_NEW_MODULE_INTERFACE/* Fetch the loaded modules, and all currently exported symbols. */static int new_get_kernel_symbols(void){ char *module_names, *mn; struct external_module *modules, *m; struct new_module_symbol *syms, *s; size_t ret, bufsize, nmod, nsyms, i, j; /* Collect the loaded modules. */ module_names = xmalloc(bufsize = 256); retry_modules_load: if (query_module(NULL, QM_MODULES, module_names, bufsize, &ret)) { if (errno == ENOSPC && bufsize < ret) { module_names = xrealloc(module_names, bufsize = ret); goto retry_modules_load; } perror_msg("QM_MODULES"); return 0; } n_ext_modules = nmod = ret; /* Collect the modules' symbols. */ if (nmod){ ext_modules = modules = xmalloc(nmod * sizeof(*modules)); memset(modules, 0, nmod * sizeof(*modules)); for (i = 0, mn = module_names, m = modules; i < nmod; ++i, ++m, mn += strlen(mn) + 1) { struct new_module_info info; if (query_module(mn, QM_INFO, &info, sizeof(info), &ret)) { if (errno == ENOENT) { /* The module was removed out from underneath us. */ continue; } perror_msg("query_module: QM_INFO: %s", mn); return 0; } syms = xmalloc(bufsize = 1024); retry_mod_sym_load: if (query_module(mn, QM_SYMBOLS, syms, bufsize, &ret)) { switch (errno) { case ENOSPC: syms = xrealloc(syms, bufsize = ret); goto retry_mod_sym_load; case ENOENT: /* The module was removed out from underneath us. */ continue; default: perror_msg("query_module: QM_SYMBOLS: %s", mn); return 0; } } nsyms = ret; m->name = mn; m->addr = info.addr; m->nsyms = nsyms; m->syms = syms; for (j = 0, s = syms; j < nsyms; ++j, ++s) { s->name += (unsigned long) syms; } } } /* Collect the kernel's symbols. */ syms = xmalloc(bufsize = 16 * 1024); retry_kern_sym_load: if (query_module(NULL, QM_SYMBOLS, syms, bufsize, &ret)) { if (errno == ENOSPC && bufsize < ret) { syms = xrealloc(syms, bufsize = ret); goto retry_kern_sym_load; } perror_msg("kernel: QM_SYMBOLS"); return 0; } nksyms = nsyms = ret; ksyms = syms; for (j = 0, s = syms; j < nsyms; ++j, ++s) { s->name += (unsigned long) syms; } return 1;}/* Return the kernel symbol checksum version, or zero if not used. */static int new_is_kernel_checksummed(void){ struct new_module_symbol *s; size_t i; /* Using_Versions is not the first symbol, but it should be in there. */ for (i = 0, s = ksyms; i < nksyms; ++i, ++s) if (strcmp((char *) s->name, "Using_Versions") == 0) return s->value; return 0;}static int new_create_this_module(struct obj_file *f, const char *m_name){ struct obj_section *sec; sec = obj_create_alloced_section_first(f, ".this", tgt_sizeof_long, sizeof(struct new_module)); memset(sec->contents, 0, sizeof(struct new_module)); obj_add_symbol(f, "__this_module", -1, ELFW(ST_INFO) (STB_LOCAL, STT_OBJECT), sec->idx, 0, sizeof(struct new_module)); obj_string_patch(f, sec->idx, offsetof(struct new_module, name), m_name); return 1;}static int new_create_module_ksymtab(struct obj_file *f){ struct obj_section *sec; int i; /* We must always add the module references. */ if (n_ext_modules_used) { struct new_module_ref *dep; struct obj_symbol *tm; sec = obj_create_alloced_section(f, ".kmodtab", tgt_sizeof_void_p, (sizeof(struct new_module_ref) * n_ext_modules_used)); if (!sec) return 0; tm = obj_find_symbol(f, "__this_module"); dep = (struct new_module_ref *) sec->contents; for (i = 0; i < n_ext_modules; ++i) if (ext_modules[i].used) { dep->dep = ext_modules[i].addr; obj_symbol_patch(f, sec->idx, (char *) &dep->ref - sec->contents, tm); dep->next_ref = 0; ++dep; } } if (flag_export && !obj_find_section(f, "__ksymtab")) { size_t nsyms; int *loaded; sec = obj_create_alloced_section(f, "__ksymtab", tgt_sizeof_void_p, 0); /* We don't want to export symbols residing in sections that aren't loaded. There are a number of these created so that we make sure certain module options don't appear twice. */ loaded = alloca(sizeof(int) * (i = f->header.e_shnum)); while (--i >= 0) loaded[i] = (f->sections[i]->header.sh_flags & SHF_ALLOC) != 0; for (nsyms = i = 0; i < HASH_BUCKETS; ++i) { struct obj_symbol *sym; for (sym = f->symtab[i]; sym; sym = sym->next) if (ELFW(ST_BIND) (sym->info) != STB_LOCAL && sym->secidx <= SHN_HIRESERVE && (sym->secidx >= SHN_LORESERVE || loaded[sym->secidx])) { ElfW(Addr) ofs = nsyms * 2 * tgt_sizeof_void_p; obj_symbol_patch(f, sec->idx, ofs, sym); obj_string_patch(f, sec->idx, ofs + tgt_sizeof_void_p, sym->name); nsyms++; } } obj_extend_section(sec, nsyms * 2 * tgt_sizeof_char_p); } return 1;}static intnew_init_module(const char *m_name, struct obj_file *f, unsigned long m_size){ struct new_module *module; struct obj_section *sec; void *image; int ret; tgt_long m_addr; sec = obj_find_section(f, ".this"); if (!sec || !sec->contents) { perror_msg_and_die("corrupt module %s?",m_name); } module = (struct new_module *) sec->contents; m_addr = sec->header.sh_addr; module->size_of_struct = sizeof(*module); module->size = m_size; module->flags = flag_autoclean ? NEW_MOD_AUTOCLEAN : 0; sec = obj_find_section(f, "__ksymtab"); if (sec && sec->header.sh_size) { module->syms = sec->header.sh_addr; module->nsyms = sec->header.sh_size / (2 * tgt_sizeof_char_p); } if (n_ext_modules_used) { sec = obj_find_section(f, ".kmodtab"); module->deps = sec->header.sh_addr; module->ndeps = n_ext_modules_used; } module->init = obj_symbol_final_value(f, obj_find_symbol(f, "init_module")); module->cleanup = obj_symbol_final_value(f, obj_find_symbol(f, "cleanup_module")); sec = obj_find_section(f, "__ex_table"); if (sec) { module->ex_table_start = sec->header.sh_addr; module->ex_table_end = sec->header.sh_addr + sec->header.sh_size; } sec = obj_find_section(f, ".text.init"); if (sec) { module->runsize = sec->header.sh_addr - m_addr; } sec = obj_find_section(f, ".data.init"); if (sec) { if (!module->runsize || module->runsize > sec->header.sh_addr - m_addr) module->runsize = sec->header.sh_addr - m_addr; } sec = obj_find_section(f, ARCHDATA_SEC_NAME); if (sec && sec->header.sh_size) { module->archdata_start = (void*)sec->header.sh_addr; module->archdata_end = module->archdata_start + sec->header.sh_size; } sec = obj_find_section(f, KALLSYMS_SEC_NAME); if (sec && sec->header.sh_size) { module->kallsyms_start = (void*)sec->header.sh_addr; module->kallsyms_end = module->kallsyms_start + sec->header.sh_size; } if (!arch_init_module(f, module)) return 0; /* Whew! All of the initialization is complete. Collect the final module image and give it to the kernel. */ image = xmalloc(m_size); obj_create_image(f, image); ret = new_sys_init_module(m_name, (struct new_module *) image); if (ret) perror_msg("init_module: %s", m_name); free(image); return ret == 0;}#else#define new_init_module(x, y, z) TRUE#define new_create_this_module(x, y) 0#define new_create_module_ksymtab(x)#define query_module(v, w, x, y, z) -1#endif /* BB_FEATURE_NEW_MODULE_INTERFACE *//*======================================================================*/static intobj_string_patch(struct obj_file *f, int secidx, ElfW(Addr) offset, const char *string){ struct obj_string_patch *p; struct obj_section *strsec; size_t len = strlen(string) + 1; char *loc; p = xmalloc(sizeof(*p)); p->next = f->string_patches; p->reloc_secidx = secidx; p->reloc_offset = offset; f->string_patches = p; strsec = obj_find_section(f, ".kstrtab"); if (strsec == NULL) { strsec = obj_create_alloced_section(f, ".kstrtab", 1, len); p->string_offset = 0; loc = strsec->contents; } else { p->string_offset = strsec->header.sh_size; loc = obj_extend_section(strsec, len); } memcpy(loc, string, len); return 1;}static intobj_symbol_patch(struct obj_file *f, int secidx, ElfW(Addr) offset, struct obj_symbol *sym){ struct obj_symbol_patch *p; p = xmalloc(sizeof(*p)); p->next = f->symbol_patches; p->reloc_secidx = secidx; p->reloc_offset = offset; p->sym = sym; f->symbol_patches = p; return 1;}static int obj_check_undefineds(struct obj_file *f){ unsigned long i; int ret = 1; for (i = 0; i < HASH_BUCKETS; ++i) { struct obj_symbol *sym; for (sym = f->symtab[i]; sym; sym = sym->next) if (sym->secidx == SHN_UNDEF) { if (ELFW(ST_BIND) (sym->info) == STB_WEAK) { sym->secidx = SHN_ABS; sym->value = 0; } else { error_msg("unresolved symbol %s", sym->name); ret = 0; } } } return ret;}static void obj_allocate_commons(struct obj_file *f){ struct common_entry { struct common_entry *next; struct obj_symbol *sym; } *common_head = NULL; unsigned long i; for (i = 0; i < HASH_BUCKETS; ++i) { struct obj_symbol *sym; for (sym = f->symtab[i]; sym; sym = sym->next) if (sym->secidx == SHN_COMMON) { /* Collect all COMMON symbols and sort them by size so as to minimize space wasted by alignment requirements. */ { struct common_entry **p, *n; for (p = &common_head; *p; p = &(*p)->next) if (sym->size <= (*p)->sym->size) break; n = alloca(sizeof(*n)); n->next = *p; n->sym = sym; *p = n; } } } for (i = 1; i < f->local_symtab_size; ++i) { struct obj_symbol *sym = f->local_symtab[i]; if (sym && sym->secidx == SHN_COMMON) { struct common_entry **p, *n; for (p = &common_head;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -