static const char *get_modinfo_value(struct obj_file *f, const char *key) { struct obj_section *sec; char *p, *v, *n, *ep; size_t klen = strlen(key); if (strcmp(key, "filename") == 0) { return(f->filename); } sec = obj_find_section(f, ".modinfo"); if (sec == NULL) return NULL; p = sec->contents; ep = p + sec->header.sh_size; while (p < ep) { v = strchr(p, '='); n = strchr(p, '\0'); if (v) { if (v - p == klen && strncmp(p, key, klen) == 0) return v + 1; } else { if (n - p == klen && strcmp(p, key) == 0) return n; } p = n + 1; } return NULL; }
/* * Extract any generic string from the given symbol. * Note: assumes same machine and arch for depmod and module. */ static void extract_generic_string(struct obj_file *f, MODULE *mod) { struct obj_section *sec; char *p, *ep, *s, **latest; sec = obj_find_section(f, ".modstring"); if (sec == NULL) return; p = sec->contents; ep = p + sec->header.sh_size; while (p < ep) { s = p; while (*p != '\0' && p < ep) p++; if (p >= ep) { bb_error_msg("unterminated generic string '%*s'", (int)(p - s), s); break; } if (p++ == s) /* empty string? */ continue; mod->generic_string = xrealloc(mod->generic_string, ++(mod->n_generic_string)*sizeof(*(mod->generic_string))); latest = mod->generic_string + mod->n_generic_string-1; *latest = bb_xstrdup(s); } }
static void show_module_parameters(struct obj_file *f, const char *format) { struct obj_section *sec; char *ptr, *value, *n, *endptr; int namelen; sec = obj_find_section(f, ".modinfo"); if (sec == NULL) { error("module does not support typed parameters"); return; } ptr = sec->contents; endptr = ptr + sec->header.sh_size; while (ptr < endptr) { value = strchr(ptr, '='); n = strchr(ptr, '\0'); if (value) { namelen = value - ptr; if (namelen >= 5 && strncmp(ptr, "parm_", 5) == 0 && !(namelen > 10 && strncmp(ptr, "parm_desc_", 10) == 0)) { char *pname = xmalloc(namelen + 1); char *desckey = xmalloc(namelen + 5 + 1); strncpy(pname, ptr + 5, namelen - 5); pname[namelen - 5] = '\0'; strcpy(desckey, "parm_desc_"); /* safe, xmalloc */ strncat(desckey, ptr + 5, namelen - 5); desckey[namelen + 5] = '\0'; format_query_line(f, format, pname, value + 1, get_modinfo_value(f, desckey)); free(pname); free(desckey); } } else { if (n - ptr >= 5 && strncmp(ptr, "parm_", 5) == 0) { error("parameter %s found with no value", ptr); } } ptr = n + 1; } }
/* * Read the symbols in an object and register them in the symbol table. * Return -1 if there is an error. */ static int loadobj(const char *objname, int ignore_suffix) { static char *currdir; static int currdir_len; int fp; MODULE *mod; SYMBOL *undefs[5000]; SYMBOL *defsym[5000]; struct obj_file *f; struct obj_section *sect; struct obj_symbol *objsym; int i; int is_2_2; int ksymtab; int len; int n_undefs = 0; int n_defsym = 0; char *p; void *image; unsigned long m_size; p = strrchr(objname, '/'); len = 1 + (int)(p - objname); if ((fp = open(objname, O_RDONLY)) < 0) return 1; if (!(f = obj_load(fp, ET_REL, objname))) { close(fp); return -1; } close(fp); /* * Allow arch code to define _GLOBAL_OFFSET_TABLE_ */ arch_create_got(f); /* * If we have changed base directory * then use the defined symbols from modules * in the _same_ directory to resolve whatever * undefined symbols there are. * * This strategy ensures that we will have * as correct dependencies as possible, * even if the same symbol is defined by * other modules in other directories. */ if (currdir_len != len || currdir == NULL || strncmp(currdir, objname, len) != 0) { if (currdir) resolve(); currdir = bb_xstrdup(objname); currdir_len = len; } mod = modules + n_modules++; mod->name = bb_xstrdup(objname); if ((sect = obj_find_section(f, "__ksymtab")) != NULL) ksymtab = sect->idx; /* Only in 2.2 (or at least not 2.0) */ else ksymtab = -1; if (sect || obj_find_section(f, ".modinfo") || obj_find_symbol(f, "__this_module")) is_2_2 = 1; else is_2_2 = 0; for (i = 0; i < HASH_BUCKETS; ++i) { for (objsym = f->symtab[i]; objsym; objsym = objsym->next) { if (objsym->secidx == SHN_UNDEF) { if (ELFW(ST_BIND)(objsym->info) != STB_WEAK && objsym->r_type /* assumes that R_arch_NONE is always 0 on all arch */) { undefs[n_undefs++] = addsym(objsym->name, mod, SYM_UNDEF, ignore_suffix); } continue; } /* else */ if (is_2_2 && ksymtab != -1) { /* A 2.2 module using EXPORT_SYMBOL */ if (objsym->secidx == ksymtab && ELFW(ST_BIND)(objsym->info) == STB_GLOBAL) { /* Ignore leading "__ksymtab_" */ defsym[n_defsym++] = addsym(objsym->name + 10, mod, SYM_DEFINED, ignore_suffix); } continue; } /* else */ if (is_2_2) { /* * A 2.2 module _not_ using EXPORT_SYMBOL * It might still want to export symbols, * although strictly speaking it shouldn't... * (Seen in pcmcia) */ if (ELFW(ST_BIND)(objsym->info) == STB_GLOBAL) { defsym[n_defsym++] = addsym(objsym->name, mod, SYM_DEFINED, ignore_suffix); } continue; } /* else */ /* Not undefined or 2.2 ksymtab entry */ if (objsym->secidx < SHN_LORESERVE /* * The test below is removed for 2.0 compatibility * since some 2.0-modules (correctly) hide the * symbols it exports via register_symtab() */ /* && ELFW(ST_BIND)(objsym->info) == STB_GLOBAL */ ) { defsym[n_defsym++] = addsym(objsym->name, mod, SYM_DEFINED, ignore_suffix); } } } /* * Finalize the information about a module. */ mod->defsym.n_syms = n_defsym; if (n_defsym > 0) { int size = n_defsym * sizeof(SYMBOL *); mod->defsym.symtab = (SYMBOL **)xmalloc(size); memcpy(mod->defsym.symtab, defsym, size); } else mod->defsym.symtab = NULL; mod->undefs.n_syms = n_undefs; if (n_undefs > 0) { int size = n_undefs * sizeof(SYMBOL *); mod->undefs.symtab = (SYMBOL **) xmalloc(size); memcpy(mod->undefs.symtab, undefs, size); mod->resolved = 0; } else { mod->undefs.symtab = NULL; mod->resolved = 1; } /* Do a pseudo relocation to base address 0x1000 (arbitrary). * All undefined symbols are treated as absolute 0. This builds * enough of a module to allow extraction of internal data such * as device tables. */ obj_clear_undefineds(f); obj_allocate_commons(f); m_size = obj_load_size(f); if (!obj_relocate(f, 0x1000)) { bb_error_msg("depmod obj_relocate failed\n"); return(-1); } extract_generic_string(f, mod); image = xmalloc(m_size); obj_create_image(f, image); free(image); obj_free(f); return 0; }