📄 insmod.c
字号:
for (i = 0; i < n_ext_modules; ++i) if (ext_modules[i].used) ref++->module = ext_modules[i].addr; } } /* Fill in routines. */ routines.init = obj_symbol_final_value(f, obj_find_symbol(f, SPFX "init_module")); routines.cleanup = obj_symbol_final_value(f, obj_find_symbol(f, SPFX "cleanup_module")); /* 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); /* image holds the complete relocated module, accounting correctly for mod_use_count. However the old module kernel support assume that it is receiving something which does not contain mod_use_count. */ ret = old_sys_init_module(m_name, image + sizeof(long), m_size | (flag_autoclean ? OLD_MOD_AUTOCLEAN : 0), &routines, symtab); if (ret) perror_msg("init_module: %s", m_name); free(image); free(symtab); return ret == 0;}#else#define old_create_mod_use_count(x) TRUE#define old_init_module(x, y, z) TRUE#endif /* CONFIG_FEATURE_OLD_MODULE_INTERFACE *//*======================================================================*//* Functions relating to module loading after 2.1.18. */static intnew_process_module_arguments(struct obj_file *f, int argc, char **argv){ while (argc > 0) { char *p, *q, *key, *sym_name; struct obj_symbol *sym; char *contents, *loc; int min, max, n; p = *argv; if ((q = strchr(p, '=')) == NULL) { argc--; continue; } key = alloca(q - p + 6); memcpy(key, "parm_", 5); memcpy(key + 5, p, q - p); key[q - p + 5] = 0; p = get_modinfo_value(f, key); key += 5; if (p == NULL) { error_msg("invalid parameter %s", key); return 0; }#ifdef SYMBOL_PREFIX sym_name = alloca (strlen (key) + sizeof SYMBOL_PREFIX); strcpy (sym_name, SYMBOL_PREFIX); strcat (sym_name, key);#else sym_name = key;#endif sym = obj_find_symbol(f, sym_name); /* Also check that the parameter was not resolved from the kernel. */ if (sym == NULL || sym->secidx > SHN_HIRESERVE) { error_msg("symbol for parameter %s not found", key); return 0; } if (isdigit(*p)) { min = strtoul(p, &p, 10); if (*p == '-') max = strtoul(p + 1, &p, 10); else max = min; } else min = max = 1; contents = f->sections[sym->secidx]->contents; loc = contents + sym->value; n = (*++q != '\0'); while (1) { if ((*p == 's') || (*p == 'c')) { char *str; /* Do C quoting if we begin with a ", else slurp the lot. */ if (*q == '"') { char *r; str = alloca(strlen(q)); for (r = str, q++; *q != '"'; ++q, ++r) { if (*q == '\0') { error_msg("improperly terminated string argument for %s", key); return 0; } else if (*q == '\\') switch (*++q) { case 'a': *r = '\a'; break; case 'b': *r = '\b'; break; case 'e': *r = '\033'; break; case 'f': *r = '\f'; break; case 'n': *r = '\n'; break; case 'r': *r = '\r'; break; case 't': *r = '\t'; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': { int c = *q - '0'; if (q[1] >= '0' && q[1] <= '7') { c = (c * 8) + *++q - '0'; if (q[1] >= '0' && q[1] <= '7') c = (c * 8) + *++q - '0'; } *r = c; } break; default: *r = *q; break; } else *r = *q; } *r = '\0'; ++q; } else { char *r; /* In this case, the string is not quoted. We will break it using the coma (like for ints). If the user wants to include comas in a string, he just has to quote it */ /* Search the next coma */ r = strchr(q, ','); /* Found ? */ if (r != (char *) NULL) { /* Recopy the current field */ 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 CONFIG_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; safe_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 /* CONFIG_FEATURE_INSMOD_VERSION_CHECKING */#ifdef CONFIG_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, SPFX "__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, SPFX "__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 =
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -