X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=modutils%2Finsmod.c;h=a6afcecea2306945e1f483463ca8ece5ff3c086d;hb=9c91e4142d5bbc74a0c4453055537931c1274757;hp=db9e1997e52d56206af401b51a7e3938f4401561;hpb=889dd20c6998c0cded684f5557748fc13a3b769e;p=oweals%2Fbusybox.git diff --git a/modutils/insmod.c b/modutils/insmod.c index db9e1997e..a6afcecea 100644 --- a/modutils/insmod.c +++ b/modutils/insmod.c @@ -2,11 +2,11 @@ /* * Mini insmod implementation for busybox * - * This version of insmod supports x86, ARM, SH3/4, powerpc, m68k, + * This version of insmod supports x86, ARM, SH3/4/5, powerpc, m68k, * MIPS, and v850e. * * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen - * Copyright (C) 1999,2000,2001,2002 by Erik Andersen + * Copyright (C) 1999-2003 by Erik Andersen * and Ron Alder * * Miles Bader added NEC V850E support. @@ -19,6 +19,11 @@ * very minor changes required to also work with StrongArm and presumably * all ARM based systems. * + * Paul Mundt 08-Aug-2003. + * Integrated support for sh64 (SH-5), from preliminary modutils + * patches from Benedict Gaster . + * Currently limited to support for 32bit ABI. + * * Magnus Damm 22-May-2002. * The plt and got code are now using the same structs. * Added generic linked list code to fully support PowerPC. @@ -102,6 +107,19 @@ #define ELFCLASSM ELFCLASS32 #endif +#if defined(__s390__) +#define CONFIG_USE_PLT_ENTRIES +#define CONFIG_PLT_ENTRY_SIZE 8 +#define CONFIG_USE_GOT_ENTRIES +#define CONFIG_GOT_ENTRY_SIZE 8 +#define CONFIG_USE_SINGLE + +#define MATCH_MACHINE(x) (x == EM_S390) +#define SHT_RELM SHT_RELA +#define Elf32_RelM Elf32_Rela +#define ELFCLASSM ELFCLASS32 +#endif + #if defined(__i386__) #define CONFIG_USE_GOT_ENTRIES #define CONFIG_GOT_ENTRY_SIZE 4 @@ -169,17 +187,18 @@ #define Elf32_RelM Elf32_Rela #define ELFCLASSM ELFCLASS32 -/* the SH changes have only been tested on the SH4 in =little endian= mode */ +/* the SH changes have only been tested in =little endian= mode */ /* I'm not sure about big endian, so let's warn: */ -#if (defined(__SH4__) || defined(__SH3__)) && defined(__BIG_ENDIAN__) -#error insmod.c may require changes for use on big endian SH4/SH3 +#if defined(__sh__) && defined(__BIG_ENDIAN__) +#error insmod.c may require changes for use on big endian SH #endif /* it may or may not work on the SH1/SH2... So let's error on those also */ -#if (defined(__sh__) && (!(defined(__SH3__) || defined(__SH4__)))) -#error insmod.c may require changes for non-SH3/SH4 use +#if ((!(defined(__SH3__) || defined(__SH4__) || defined(__SH5__)))) && \ + (defined(__sh__)) +#error insmod.c may require changes for SH1 or SH2 use #endif #endif @@ -234,7 +253,7 @@ #ifndef MODUTILS_MODULE_H static const int MODUTILS_MODULE_H = 1; -#ident "$Id: insmod.c,v 1.93 2003/01/23 04:48:34 andersen Exp $" +#ident "$Id: insmod.c,v 1.103 2003/09/03 00:42:58 bug1 Exp $" /* This file contains the structures used by the 2.0 and 2.1 kernels. We do not use the kernel headers directly because we do not wish @@ -455,7 +474,7 @@ int delete_module(const char *); #ifndef MODUTILS_OBJ_H static const int MODUTILS_OBJ_H = 1; -#ident "$Id: insmod.c,v 1.93 2003/01/23 04:48:34 andersen Exp $" +#ident "$Id: insmod.c,v 1.103 2003/09/03 00:42:58 bug1 Exp $" /* The relocatable object is manipulated using elfin types. */ @@ -479,7 +498,7 @@ static const int MODUTILS_OBJ_H = 1; # endif #endif -/* For some reason this is missing from libc5. */ +/* For some reason this is missing from some ancient C libraries.... */ #ifndef ELF32_ST_INFO # define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) #endif @@ -631,6 +650,8 @@ static enum obj_reloc arch_apply_relocation (struct obj_file *f, static void arch_create_got (struct obj_file *f); +static int obj_gpl_license(struct obj_file *f, const char **license); + #ifdef CONFIG_FEATURE_NEW_MODULE_INTERFACE static int arch_init_module (struct obj_file *f, struct new_module *); #endif @@ -641,7 +662,6 @@ static int arch_init_module (struct obj_file *f, struct new_module *); //---------------------------------------------------------------------------- - /* SPFX is always a string, so it can be concatenated to string constants. */ #ifdef SYMBOL_PREFIX #define SPFX SYMBOL_PREFIX @@ -756,12 +776,12 @@ static int check_module_name_match(const char *filename, struct stat *statbuf, if (fullname[0] == '\0') return (FALSE); else { - char *tmp, *tmp1 = xstrdup(filename); - tmp = get_last_path_component(tmp1); + char *tmp, *tmp1 = bb_xstrdup(filename); + tmp = bb_get_last_path_component(tmp1); if (strcmp(tmp, fullname) == 0) { free(tmp1); /* Stop searching if we find a match */ - m_filename = xstrdup(filename); + m_filename = bb_xstrdup(filename); return (TRUE); } free(tmp1); @@ -856,6 +876,89 @@ arch_apply_relocation(struct obj_file *f, *loc += v - got; break; +#elif defined(__s390__) + case R_390_32: + *(unsigned int *) loc += v; + break; + case R_390_16: + *(unsigned short *) loc += v; + break; + case R_390_8: + *(unsigned char *) loc += v; + break; + + case R_390_PC32: + *(unsigned int *) loc += v - dot; + break; + case R_390_PC16DBL: + *(unsigned short *) loc += (v - dot) >> 1; + break; + case R_390_PC16: + *(unsigned short *) loc += v - dot; + break; + + case R_390_PLT32: + case R_390_PLT16DBL: + /* find the plt entry and initialize it. */ + assert(isym != NULL); + pe = (struct arch_single_entry *) &isym->pltent; + assert(pe->allocated); + if (pe->inited == 0) { + ip = (unsigned long *)(ifile->plt->contents + pe->offset); + ip[0] = 0x0d105810; /* basr 1,0; lg 1,10(1); br 1 */ + ip[1] = 0x100607f1; + if (ELF32_R_TYPE(rel->r_info) == R_390_PLT16DBL) + ip[2] = v - 2; + else + ip[2] = v; + pe->inited = 1; + } + + /* Insert relative distance to target. */ + v = plt + pe->offset - dot; + if (ELF32_R_TYPE(rel->r_info) == R_390_PLT32) + *(unsigned int *) loc = (unsigned int) v; + else if (ELF32_R_TYPE(rel->r_info) == R_390_PLT16DBL) + *(unsigned short *) loc = (unsigned short) ((v + 2) >> 1); + break; + + case R_390_GLOB_DAT: + case R_390_JMP_SLOT: + *loc = v; + break; + + case R_390_RELATIVE: + *loc += f->baseaddr; + break; + + case R_390_GOTPC: + assert(got != 0); + *(unsigned long *) loc += got - dot; + break; + + case R_390_GOT12: + case R_390_GOT16: + case R_390_GOT32: + assert(isym != NULL); + assert(got != 0); + if (!isym->gotent.inited) + { + isym->gotent.inited = 1; + *(Elf32_Addr *)(ifile->got->contents + isym->gotent.offset) = v; + } + if (ELF32_R_TYPE(rel->r_info) == R_390_GOT12) + *(unsigned short *) loc |= (*(unsigned short *) loc + isym->gotent.offset) & 0xfff; + else if (ELF32_R_TYPE(rel->r_info) == R_390_GOT16) + *(unsigned short *) loc += isym->gotent.offset; + else if (ELF32_R_TYPE(rel->r_info) == R_390_GOT32) + *(unsigned int *) loc += isym->gotent.offset; + break; + + case R_390_GOTOFF: + assert(got != 0); + *loc += v - got; + break; + #elif defined(__i386__) case R_386_NONE: @@ -1105,7 +1208,51 @@ arch_apply_relocation(struct obj_file *f, *loc = v - got; break; -#endif +#if defined(__SH5__) + case R_SH_IMM_MEDLOW16: + case R_SH_IMM_LOW16: + { + Elf32_Addr word; + + if (ELF32_R_TYPE(rel->r_info) == R_SH_IMM_MEDLOW16) + v >>= 16; + + /* + * movi and shori have the format: + * + * | op | imm | reg | reserved | + * 31..26 25..10 9.. 4 3 .. 0 + * + * so we simply mask and or in imm. + */ + word = *loc & ~0x3fffc00; + word |= (v & 0xffff) << 10; + + *loc = word; + + break; + } + + case R_SH_IMM_MEDLOW16_PCREL: + case R_SH_IMM_LOW16_PCREL: + { + Elf32_Addr word; + + word = *loc & ~0x3fffc00; + + v -= dot; + + if (ELF32_R_TYPE(rel->r_info) == R_SH_IMM_MEDLOW16_PCREL) + v >>= 16; + + word |= (v & 0xffff) << 10; + + *loc = word; + + break; + } +#endif /* __SH5__ */ +#endif /* __sh__ */ default: printf("Warning: unhandled reloc %d\n",(int)ELF32_R_TYPE(rel->r_info)); @@ -1604,7 +1751,7 @@ obj_add_symbol(struct obj_file *f, const char *name, /* Don't report an error if the symbol is coming from the kernel or some external module. */ if (secidx <= SHN_HIRESERVE) - error_msg("%s multiply defined", name); + bb_error_msg("%s multiply defined", name); return sym; } } @@ -1617,7 +1764,7 @@ obj_add_symbol(struct obj_file *f, const char *name, if (ELFW(ST_BIND)(info) == STB_LOCAL && symidx != -1) { if (symidx >= f->local_symtab_size) - error_msg("local symbol %s with index %ld exceeds local_symtab_size %ld", + bb_error_msg("local symbol %s with index %ld exceeds local_symtab_size %ld", name, (long) symidx, (long) f->local_symtab_size); else f->local_symtab[symidx] = sym; @@ -1785,14 +1932,34 @@ add_symbols_from( char *name_buf = 0; size_t name_alloced_size = 0; #endif +#ifdef CONFIG_FEATURE_CHECK_TAINTED_MODULE + int gpl; + gpl = obj_gpl_license(f, NULL) == 0; +#endif for (i = 0, s = syms; i < nsyms; ++i, ++s) { /* Only add symbols that are already marked external. If we override locals we may cause problems for argument initialization. We will also create a false dependency on the module. */ struct obj_symbol *sym; - char *name = (char *)s->name; + char *name; + + /* GPL licensed modules can use symbols exported with + * EXPORT_SYMBOL_GPL, so ignore any GPLONLY_ prefix on the + * exported names. Non-GPL modules never see any GPLONLY_ + * symbols so they cannot fudge it by adding the prefix on + * their references. + */ + if (strncmp((char *)s->name, "GPLONLY_", 8) == 0) { +#ifdef CONFIG_FEATURE_CHECK_TAINTED_MODULE + if (gpl) + ((char *)s->name) += 8; + else +#endif + continue; + } + name = (char *)s->name; #ifdef SYMBOL_PREFIX /* Prepend SYMBOL_PREFIX to the symbol's name (the @@ -1900,7 +2067,7 @@ old_process_module_arguments(struct obj_file *f, int argc, char **argv) /* 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", p); + bb_error_msg("symbol for parameter %s not found", p); return 0; } @@ -1913,7 +2080,7 @@ old_process_module_arguments(struct obj_file *f, int argc, char **argv) str = alloca(strlen(q)); for (r = str, q++; *q != '"'; ++q, ++r) { if (*q == '\0') { - error_msg("improperly terminated string argument for %s", p); + bb_error_msg("improperly terminated string argument for %s", p); return 0; } else if (*q == '\\') switch (*++q) { @@ -2043,9 +2210,9 @@ static int old_get_kernel_symbols(const char *m_name) nks = get_kernel_syms(NULL); if (nks <= 0) { if (nks) - perror_msg("get_kernel_syms: %s", m_name); + bb_perror_msg("get_kernel_syms: %s", m_name); else - error_msg("No kernel symbols"); + bb_error_msg("No kernel symbols"); return 0; } @@ -2226,7 +2393,7 @@ old_init_module(const char *m_name, struct obj_file *f, m_size | (flag_autoclean ? OLD_MOD_AUTOCLEAN : 0), &routines, symtab); if (ret) - perror_msg("init_module: %s", m_name); + bb_perror_msg("init_module: %s", m_name); free(image); free(symtab); @@ -2269,7 +2436,7 @@ new_process_module_arguments(struct obj_file *f, int argc, char **argv) p = get_modinfo_value(f, key); key += 5; if (p == NULL) { - error_msg("invalid parameter %s", key); + bb_error_msg("invalid parameter %s", key); return 0; } @@ -2284,7 +2451,7 @@ new_process_module_arguments(struct obj_file *f, int argc, char **argv) /* 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); + bb_error_msg("symbol for parameter %s not found", key); return 0; } @@ -2312,7 +2479,7 @@ new_process_module_arguments(struct obj_file *f, int argc, char **argv) str = alloca(strlen(q)); for (r = str, q++; *q != '"'; ++q, ++r) { if (*q == '\0') { - error_msg("improperly terminated string argument for %s", + bb_error_msg("improperly terminated string argument for %s", key); return 0; } else if (*q == '\\') @@ -2406,7 +2573,7 @@ new_process_module_arguments(struct obj_file *f, int argc, char **argv) /* 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" + bb_error_msg("parameter type 'c' for %s must be followed by" " the maximum size", key); return 0; } @@ -2414,7 +2581,7 @@ new_process_module_arguments(struct obj_file *f, int argc, char **argv) /* Check length */ if (strlen(str) >= charssize) { - error_msg("string too long for %s (max %ld)", key, + bb_error_msg("string too long for %s (max %ld)", key, charssize - 1); return 0; } @@ -2443,7 +2610,7 @@ new_process_module_arguments(struct obj_file *f, int argc, char **argv) break; default: - error_msg("unknown parameter type '%c' for %s", *p, key); + bb_error_msg("unknown parameter type '%c' for %s", *p, key); return 0; } } @@ -2462,21 +2629,21 @@ new_process_module_arguments(struct obj_file *f, int argc, char **argv) case ',': if (++n > max) { - error_msg("too many values for %s (max %d)", key, max); + bb_error_msg("too many values for %s (max %d)", key, max); return 0; } ++q; break; default: - error_msg("invalid argument syntax for %s", key); + bb_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); + bb_error_msg("too few values for %s (min %d)", key, min); return 0; } @@ -2545,7 +2712,7 @@ static int new_get_kernel_symbols(void) module_names = xrealloc(module_names, bufsize = ret); goto retry_modules_load; } - perror_msg("QM_MODULES"); + bb_perror_msg("QM_MODULES"); return 0; } @@ -2565,7 +2732,7 @@ static int new_get_kernel_symbols(void) /* The module was removed out from underneath us. */ continue; } - perror_msg("query_module: QM_INFO: %s", mn); + bb_perror_msg("query_module: QM_INFO: %s", mn); return 0; } @@ -2580,7 +2747,7 @@ static int new_get_kernel_symbols(void) /* The module was removed out from underneath us. */ continue; default: - perror_msg("query_module: QM_SYMBOLS: %s", mn); + bb_perror_msg("query_module: QM_SYMBOLS: %s", mn); return 0; } } @@ -2606,7 +2773,7 @@ static int new_get_kernel_symbols(void) syms = xrealloc(syms, bufsize = ret); goto retry_kern_sym_load; } - perror_msg("kernel: QM_SYMBOLS"); + bb_perror_msg("kernel: QM_SYMBOLS"); return 0; } nksyms = nsyms = ret; @@ -2767,7 +2934,7 @@ new_init_module(const char *m_name, struct obj_file *f, sec = obj_find_section(f, ".this"); if (!sec || !sec->contents) { - perror_msg_and_die("corrupt module %s?",m_name); + bb_perror_msg_and_die("corrupt module %s?",m_name); } module = (struct new_module *) sec->contents; m_addr = sec->header.sh_addr; @@ -2831,7 +2998,7 @@ new_init_module(const char *m_name, struct obj_file *f, ret = new_sys_init_module(m_name, (struct new_module *) image); if (ret) - perror_msg("init_module: %s", m_name); + bb_perror_msg("init_module: %s", m_name); free(image); @@ -2912,7 +3079,7 @@ static int obj_check_undefineds(struct obj_file *f) sym->value = 0; } else { if (!flag_quiet) { - error_msg("unresolved symbol %s", sym->name); + bb_error_msg("unresolved symbol %s", sym->name); } ret = 0; } @@ -3140,11 +3307,11 @@ static int obj_relocate(struct obj_file *f, ElfW(Addr) base) errmsg = "Unhandled relocation"; bad_reloc: if (extsym) { - error_msg("%s of type %ld for %s", errmsg, + bb_error_msg("%s of type %ld for %s", errmsg, (long) ELFW(R_TYPE) (rel->r_info), strtab + extsym->st_name); } else { - error_msg("%s of type %ld", errmsg, + bb_error_msg("%s of type %ld", errmsg, (long) ELFW(R_TYPE) (rel->r_info)); } ret = 0; @@ -3221,7 +3388,7 @@ static struct obj_file *obj_load(FILE * fp, int loadprogbits) fseek(fp, 0, SEEK_SET); if (fread(&f->header, sizeof(f->header), 1, fp) != 1) { - perror_msg("error reading ELF header"); + bb_perror_msg("error reading ELF header"); return NULL; } @@ -3229,25 +3396,25 @@ static struct obj_file *obj_load(FILE * fp, int loadprogbits) || f->header.e_ident[EI_MAG1] != ELFMAG1 || f->header.e_ident[EI_MAG2] != ELFMAG2 || f->header.e_ident[EI_MAG3] != ELFMAG3) { - error_msg("not an ELF file"); + bb_error_msg("not an ELF file"); return NULL; } if (f->header.e_ident[EI_CLASS] != ELFCLASSM || f->header.e_ident[EI_DATA] != ELFDATAM || f->header.e_ident[EI_VERSION] != EV_CURRENT || !MATCH_MACHINE(f->header.e_machine)) { - error_msg("ELF file not for this architecture"); + bb_error_msg("ELF file not for this architecture"); return NULL; } if (f->header.e_type != ET_REL) { - error_msg("ELF file not a relocatable object"); + bb_error_msg("ELF file not a relocatable object"); return NULL; } /* Read the section headers. */ if (f->header.e_shentsize != sizeof(ElfW(Shdr))) { - error_msg("section header size mismatch: %lu != %lu", + bb_error_msg("section header size mismatch: %lu != %lu", (unsigned long) f->header.e_shentsize, (unsigned long) sizeof(ElfW(Shdr))); return NULL; @@ -3260,7 +3427,7 @@ static struct obj_file *obj_load(FILE * fp, int loadprogbits) section_headers = alloca(sizeof(ElfW(Shdr)) * shnum); fseek(fp, f->header.e_shoff, SEEK_SET); if (fread(section_headers, sizeof(ElfW(Shdr)), shnum, fp) != shnum) { - perror_msg("error reading ELF section headers"); + bb_perror_msg("error reading ELF section headers"); return NULL; } @@ -3296,7 +3463,7 @@ static struct obj_file *obj_load(FILE * fp, int loadprogbits) sec->contents = xmalloc(sec->header.sh_size); fseek(fp, sec->header.sh_offset, SEEK_SET); if (fread(sec->contents, sec->header.sh_size, 1, fp) != 1) { - perror_msg("error reading ELF section data"); + bb_perror_msg("error reading ELF section data"); return NULL; } } else { @@ -3306,11 +3473,11 @@ static struct obj_file *obj_load(FILE * fp, int loadprogbits) #if SHT_RELM == SHT_REL case SHT_RELA: - error_msg("RELA relocations not supported on this architecture"); + bb_error_msg("RELA relocations not supported on this architecture"); return NULL; #else case SHT_REL: - error_msg("REL relocations not supported on this architecture"); + bb_error_msg("REL relocations not supported on this architecture"); return NULL; #endif @@ -3323,7 +3490,7 @@ static struct obj_file *obj_load(FILE * fp, int loadprogbits) break; } - error_msg("can't handle sections of type %ld", + bb_error_msg("can't handle sections of type %ld", (long) sec->header.sh_type); return NULL; } @@ -3358,7 +3525,7 @@ static struct obj_file *obj_load(FILE * fp, int loadprogbits) ElfW(Sym) * sym; if (sec->header.sh_entsize != sizeof(ElfW(Sym))) { - error_msg("symbol size mismatch: %lu != %lu", + bb_error_msg("symbol size mismatch: %lu != %lu", (unsigned long) sec->header.sh_entsize, (unsigned long) sizeof(ElfW(Sym))); return NULL; @@ -3374,21 +3541,33 @@ static struct obj_file *obj_load(FILE * fp, int loadprogbits) /* Insert all symbols into the hash table. */ for (j = 1, ++sym; j < nsym; ++j, ++sym) { + ElfW(Addr) val = sym->st_value; const char *name; if (sym->st_name) name = strtab + sym->st_name; else name = f->sections[sym->st_shndx]->name; +#if defined(__SH5__) + /* + * For sh64 it is possible that the target of a branch + * requires a mode switch (32 to 16 and back again). + * + * This is implied by the lsb being set in the target + * address for SHmedia mode and clear for SHcompact. + */ + val |= sym->st_other & 4; +#endif + obj_add_symbol(f, name, j, sym->st_info, sym->st_shndx, - sym->st_value, sym->st_size); + val, sym->st_size); } } break; case SHT_RELM: if (sec->header.sh_entsize != sizeof(ElfW(RelM))) { - error_msg("relocation entry size mismatch: %lu != %lu", + bb_error_msg("relocation entry size mismatch: %lu != %lu", (unsigned long) sec->header.sh_entsize, (unsigned long) sizeof(ElfW(RelM))); return NULL; @@ -3427,7 +3606,7 @@ static int obj_load_progbits(FILE * fp, struct obj_file* f, char* imagebase) sec->contents = imagebase + (sec->header.sh_addr - base); fseek(fp, sec->header.sh_offset, SEEK_SET); if (fread(sec->contents, sec->header.sh_size, 1, fp) != 1) { - error_msg("error reading ELF section data: %s\n", strerror(errno)); + bb_error_msg("error reading ELF section data: %s\n", strerror(errno)); return 0; } @@ -3454,6 +3633,7 @@ static void hide_special_symbols(struct obj_file *f) ELFW(ST_INFO) (STB_LOCAL, ELFW(ST_TYPE) (sym->info)); } + #ifdef CONFIG_FEATURE_CHECK_TAINTED_MODULE static int obj_gpl_license(struct obj_file *f, const char **license) { @@ -3614,14 +3794,14 @@ add_ksymoops_symbols(struct obj_file *f, const char *filename, }; if (realpath(filename, real)) { - absolute_filename = xstrdup(real); + absolute_filename = bb_xstrdup(real); } else { int save_errno = errno; - error_msg("cannot get realpath for %s", filename); + bb_error_msg("cannot get realpath for %s", filename); errno = save_errno; perror(""); - absolute_filename = xstrdup(filename); + absolute_filename = bb_xstrdup(filename); } lm_name = strlen(m_name); @@ -3706,6 +3886,98 @@ add_ksymoops_symbols(struct obj_file *f, const char *filename, } #endif /* CONFIG_FEATURE_INSMOD_KSYMOOPS_SYMBOLS */ +#ifdef CONFIG_FEATURE_INSMOD_LOAD_MAP +static void print_load_map(struct obj_file *f) +{ + struct obj_symbol *sym; + struct obj_symbol **all, **p; + struct obj_section *sec; + int i, nsyms, *loaded; + + /* Report on the section layout. */ + + printf("Sections: Size %-*s Align\n", + (int) (2 * sizeof(void *)), "Address"); + + for (sec = f->load_order; sec; sec = sec->load_next) { + int a; + unsigned long tmp; + + for (a = -1, tmp = sec->header.sh_addralign; tmp; ++a) + tmp >>= 1; + if (a == -1) + a = 0; + + printf("%-15s %08lx %0*lx 2**%d\n", + sec->name, + (long)sec->header.sh_size, + (int) (2 * sizeof(void *)), + (long)sec->header.sh_addr, + a); + } +#ifdef CONFIG_FEATURE_INSMOD_LOAD_MAP_FULL + /* Quick reference which section indicies are loaded. */ + + loaded = alloca(sizeof(int) * (i = f->header.e_shnum)); + while (--i >= 0) + loaded[i] = (f->sections[i]->header.sh_flags & SHF_ALLOC) != 0; + + /* Collect the symbols we'll be listing. */ + + for (nsyms = i = 0; i < HASH_BUCKETS; ++i) + for (sym = f->symtab[i]; sym; sym = sym->next) + if (sym->secidx <= SHN_HIRESERVE + && (sym->secidx >= SHN_LORESERVE || loaded[sym->secidx])) + ++nsyms; + + all = alloca(nsyms * sizeof(struct obj_symbol *)); + + for (i = 0, p = all; i < HASH_BUCKETS; ++i) + for (sym = f->symtab[i]; sym; sym = sym->next) + if (sym->secidx <= SHN_HIRESERVE + && (sym->secidx >= SHN_LORESERVE || loaded[sym->secidx])) + *p++ = sym; + + /* And list them. */ + printf("\nSymbols:\n"); + for (p = all; p < all + nsyms; ++p) { + char type = '?'; + unsigned long value; + + sym = *p; + if (sym->secidx == SHN_ABS) { + type = 'A'; + value = sym->value; + } else if (sym->secidx == SHN_UNDEF) { + type = 'U'; + value = 0; + } else { + sec = f->sections[sym->secidx]; + + if (sec->header.sh_type == SHT_NOBITS) + type = 'B'; + else if (sec->header.sh_flags & SHF_ALLOC) { + if (sec->header.sh_flags & SHF_EXECINSTR) + type = 'T'; + else if (sec->header.sh_flags & SHF_WRITE) + type = 'D'; + else + type = 'R'; + } + value = sym->value + sec->header.sh_addr; + } + + if (ELFW(ST_BIND) (sym->info) == STB_LOCAL) + type = tolower(type); + + printf("%0*lx %c %s\n", (int) (2 * sizeof(void *)), value, + type, sym->name); + } +#endif +} + +#endif + extern int insmod_main( int argc, char **argv) { int opt; @@ -3731,9 +4003,16 @@ extern int insmod_main( int argc, char **argv) #else FILE *fp; #endif +#ifdef CONFIG_FEATURE_INSMOD_LOAD_MAP + int flag_print_load_map = 0; +#endif /* Parse any options */ +#ifdef CONFIG_FEATURE_INSMOD_LOAD_MAP + while ((opt = getopt(argc, argv, "fkqsvxmLo:")) > 0) { +#else while ((opt = getopt(argc, argv, "fkqsvxLo:")) > 0) { +#endif switch (opt) { case 'f': /* force loading */ flag_force_load = 1; @@ -3758,7 +4037,7 @@ extern int insmod_main( int argc, char **argv) break; case 'o': /* name the output module */ free(m_name); - m_name = xstrdup(optarg); + m_name = bb_xstrdup(optarg); break; case 'L': /* Stub warning */ /* This is needed for compatibility with modprobe. @@ -3766,17 +4045,22 @@ extern int insmod_main( int argc, char **argv) * that. So be careful and plan your life around not * loading the same module 50 times concurrently. */ break; +#ifdef CONFIG_FEATURE_INSMOD_LOAD_MAP + case 'm': /* print module load map */ + flag_print_load_map = 1; + break; +#endif default: - show_usage(); + bb_show_usage(); } } if (argv[optind] == NULL) { - show_usage(); + bb_show_usage(); } /* Grab the module name */ - tmp1 = xstrdup(argv[optind]); + tmp1 = bb_xstrdup(argv[optind]); tmp = basename(tmp1); len = strlen(tmp); @@ -3785,7 +4069,7 @@ extern int insmod_main( int argc, char **argv) tmp[len] = '\0'; } - bb_asprintf(&m_fullName, "%s.o", tmp); + bb_xasprintf(&m_fullName, "%s.o", tmp); if (!m_name) { m_name = tmp; @@ -3838,19 +4122,27 @@ extern int insmod_main( int argc, char **argv) if (m_filename == 0 || ((fp = fopen(m_filename, "r")) == NULL)) { - error_msg("%s: no module by that name found", m_fullName); + bb_error_msg("%s: no module by that name found", m_fullName); goto out; } } else - error_msg_and_die("%s: no module by that name found", m_fullName); + bb_error_msg_and_die("%s: no module by that name found", m_fullName); } } else - m_filename = xstrdup(argv[optind]); + m_filename = bb_xstrdup(argv[optind]); printf("Using %s\n", m_filename); +#ifdef CONFIG_FEATURE_REALLY_NEW_MODULE_INTERFACE + if (create_module(NULL, 0) < 0 && errno == ENOSYS) { + optind--; + argv[optind] = m_filename; + return insmod_ng_main(argc - optind, argv + optind); + } +#endif + if ((f = obj_load(fp, LOADBITS)) == NULL) - perror_msg_and_die("Could not load the module"); + bb_perror_msg_and_die("Could not load the module"); if (get_modinfo_value(f, "kernel_version") == NULL) m_has_modinfo = 0; @@ -3867,7 +4159,7 @@ extern int insmod_main( int argc, char **argv) } else { m_version = old_get_module_version(f, m_strversion); if (m_version == -1) { - error_msg("couldn't find the kernel version the module was " + bb_error_msg("couldn't find the kernel version the module was " "compiled for"); goto out; } @@ -3875,12 +4167,12 @@ extern int insmod_main( int argc, char **argv) if (strncmp(uts_info.release, m_strversion, STRVERSIONLEN) != 0) { if (flag_force_load) { - error_msg("Warning: kernel-module version mismatch\n" + bb_error_msg("Warning: kernel-module version mismatch\n" "\t%s was compiled for kernel version %s\n" "\twhile this kernel is version %s", m_filename, m_strversion, uts_info.release); } else { - error_msg("kernel-module version mismatch\n" + bb_error_msg("kernel-module version mismatch\n" "\t%s was compiled for kernel version %s\n" "\twhile this kernel is version %s.", m_filename, m_strversion, uts_info.release); @@ -3899,7 +4191,7 @@ extern int insmod_main( int argc, char **argv) goto out; k_crcs = new_is_kernel_checksummed(); #else - error_msg("Not configured to support new kernels"); + bb_error_msg("Not configured to support new kernels"); goto out; #endif } else { @@ -3908,7 +4200,7 @@ extern int insmod_main( int argc, char **argv) goto out; k_crcs = old_is_kernel_checksummed(); #else - error_msg("Not configured to support old kernels"); + bb_error_msg("Not configured to support old kernels"); goto out; #endif } @@ -3970,14 +4262,14 @@ extern int insmod_main( int argc, char **argv) m_addr = create_module(m_name, m_size); if (m_addr == -1) switch (errno) { case EEXIST: - error_msg("A module named %s already exists", m_name); + bb_error_msg("A module named %s already exists", m_name); goto out; case ENOMEM: - error_msg("Can't allocate kernel memory for module; needed %lu bytes", + bb_error_msg("Can't allocate kernel memory for module; needed %lu bytes", m_size); goto out; default: - perror_msg("create_module: %s", m_name); + bb_perror_msg("create_module: %s", m_name); goto out; } @@ -4005,6 +4297,11 @@ extern int insmod_main( int argc, char **argv) goto out; } +#ifdef CONFIG_FEATURE_INSMOD_LOAD_MAP + if(flag_print_load_map) + print_load_map(f); +#endif + exit_status = EXIT_SUCCESS; out: