diff options
-rw-r--r-- | sys/kern/kern_linker.c | 610 | ||||
-rw-r--r-- | sys/kern/kern_module.c | 17 | ||||
-rw-r--r-- | sys/kern/link_aout.c | 116 | ||||
-rw-r--r-- | sys/kern/link_elf.c | 132 | ||||
-rw-r--r-- | sys/kern/link_elf_obj.c | 132 | ||||
-rw-r--r-- | sys/kern/linker_if.m | 8 | ||||
-rw-r--r-- | sys/sys/linker.h | 13 | ||||
-rw-r--r-- | sys/sys/module.h | 62 |
8 files changed, 705 insertions, 385 deletions
diff --git a/sys/kern/kern_linker.c b/sys/kern/kern_linker.c index a3193e5..7fc8a2f 100644 --- a/sys/kern/kern_linker.c +++ b/sys/kern/kern_linker.c @@ -52,8 +52,11 @@ int kld_debug = 0; #endif -MALLOC_DEFINE(M_LINKER, "kld", "kernel linker"); -linker_file_t linker_current_file; +static char *linker_search_path(const char *name); +static const char *linker_basename(const char* path); + +MALLOC_DEFINE(M_LINKER, "linker", "kernel linker"); + linker_file_t linker_kernel_file; static struct lock lock; /* lock for the file list */ @@ -61,6 +64,16 @@ static linker_class_list_t classes; static linker_file_list_t linker_files; static int next_file_id = 1; +/* XXX wrong name; we're looking at version provision tags here, not modules */ +typedef TAILQ_HEAD(, modlist) modlisthead_t; +struct modlist { + TAILQ_ENTRY(modlist) link; /* chain together all modules */ + linker_file_t container; + const char *name; +}; +typedef struct modlist *modlist_t; +static modlisthead_t found_modules; + static char * linker_strdup(const char *str) { @@ -85,7 +98,7 @@ int linker_add_class(linker_class_t lc) { kobj_class_compile((kobj_class_t) lc); - TAILQ_INSERT_HEAD(&classes, lc, link); + TAILQ_INSERT_TAIL(&classes, lc, link); return 0; } @@ -96,8 +109,6 @@ linker_file_sysinit(linker_file_t lf) struct sysinit** sipp; struct sysinit** xipp; struct sysinit* save; - const moduledata_t *moddata; - int error; KLD_DPF(FILE, ("linker_file_sysinit: calling SYSINITs for %s\n", lf->filename)); @@ -108,18 +119,6 @@ linker_file_sysinit(linker_file_t lf) KLD_DPF(FILE, ("linker_file_sysinit: SYSINITs %p\n", sysinits)); if (!sysinits) return; - - /* HACK ALERT! */ - for (sipp = (struct sysinit **)sysinits->ls_items; *sipp; sipp++) { - if ((*sipp)->func == module_register_init) { - moddata = (*sipp)->udata; - error = module_register(moddata, lf); - if (error) - printf("linker_file_sysinit \"%s\" failed to register! %d\n", - lf->filename, error); - } - } - /* * Perform a bubble sort of the system initialization objects by * their subsystem (primary key) and order (secondary key). @@ -190,7 +189,6 @@ linker_file_sysuninit(linker_file_t lf) } } - /* * Traverse the (now) ordered list of system initialization tasks. * Perform each task, and continue on to the next task. @@ -240,13 +238,69 @@ linker_file_unregister_sysctls(linker_file_t lf) sysctl_unregister_set(sysctls); } +static int +linker_file_register_modules(linker_file_t lf) +{ + int error, mcount; + struct linker_set *modules; + struct mod_metadata **mdpp; + const moduledata_t *moddata; + struct sysinit **sipp; + + KLD_DPF(FILE, ("linker_file_register_modules: registering modules in %s\n", + lf->filename)); + + modules = (struct linker_set*) + linker_file_lookup_symbol(lf, "modmetadata_set", 0); + mcount = 0; + if (modules) { + for (mdpp = (struct mod_metadata**)modules->ls_items; *mdpp; mdpp++) { + if ((*mdpp)->md_type != MDT_MODULE) + continue; + mcount++; + moddata = (*mdpp)->md_data; + KLD_DPF(FILE, ("Registering module %s in %s\n", + moddata->name, lf->filename)); + error = module_register(moddata, lf); + if (error) + printf("Module %s failed to register: %d\n", moddata->name, error); + } + } + if (mcount) + return mcount; /* Do not mix old and new style */ + + /* Hack - handle old kld's without metadata */ + modules = (struct linker_set*) + linker_file_lookup_symbol(lf, "sysinit_set", 0); + if (modules) { + for (sipp = (struct sysinit **)modules->ls_items; *sipp; sipp++) { + if ((*sipp)->func != module_register_init) + continue; + mcount++; + moddata = (*sipp)->udata; + printf("Old-style KLD file %s found\n", moddata->name); + error = module_register(moddata, lf); + if (error) + printf("Old-style KLD file %s failed to register: %d\n", moddata->name, error); + } + } + return mcount; +} + +static void +linker_init_kernel_modules(void) +{ + linker_file_register_modules(linker_kernel_file); +} + +SYSINIT(linker_kernel, SI_SUB_KLD, SI_ORDER_ANY, linker_init_kernel_modules, 0); + int linker_load_file(const char* filename, linker_file_t* result) { linker_class_t lc; linker_file_t lf; int foundfile, error = 0; - char *koname = NULL; lf = linker_find_file_by_name(filename); if (lf) { @@ -256,21 +310,12 @@ linker_load_file(const char* filename, linker_file_t* result) goto out; } - koname = malloc(strlen(filename) + 4, M_LINKER, M_WAITOK); - if (koname == NULL) { - error = ENOMEM; - goto out; - } - sprintf(koname, "%s.ko", filename); lf = NULL; foundfile = 0; for (lc = TAILQ_FIRST(&classes); lc; lc = TAILQ_NEXT(lc, link)) { KLD_DPF(FILE, ("linker_load_file: trying to load %s as %s\n", filename, lc->desc)); - - error = LINKER_LOAD_FILE(lc, koname, &lf); /* First with .ko */ - if (lf == NULL && error == ENOENT) - error = LINKER_LOAD_FILE(lc, filename, &lf); /* Then try without */ + error = LINKER_LOAD_FILE(lc, filename, &lf); /* * If we got something other than ENOENT, then it exists but we cannot * load it for some other reason. @@ -278,8 +323,10 @@ linker_load_file(const char* filename, linker_file_t* result) if (error != ENOENT) foundfile = 1; if (lf) { + linker_file_register_modules(lf); linker_file_register_sysctls(lf); linker_file_sysinit(lf); + lf->flags |= LINKER_FILE_LINKED; *result = lf; error = 0; @@ -296,8 +343,6 @@ linker_load_file(const char* filename, linker_file_t* result) error = ENOENT; /* Nothing found */ out: - if (koname) - free(koname, M_LINKER); return error; } @@ -347,11 +392,7 @@ linker_make_file(const char* pathname, linker_class_t lc) linker_file_t lf = 0; const char *filename; - filename = rindex(pathname, '/'); - if (filename && filename[1]) - filename++; - else - filename = pathname; + filename = linker_basename(pathname); KLD_DPF(FILE, ("linker_make_file: new file, filename=%s\n", filename)); lockmgr(&lock, LK_EXCLUSIVE, 0, curproc); @@ -380,6 +421,7 @@ int linker_file_unload(linker_file_t file) { module_t mod, next; + modlist_t ml, nextml; struct common_symbol* cp; int error = 0; int i; @@ -414,6 +456,13 @@ linker_file_unload(linker_file_t file) goto out; } + for (ml = TAILQ_FIRST(&found_modules); ml; ml = nextml) { + nextml = TAILQ_NEXT(ml, link); + if (ml->container == file) { + TAILQ_REMOVE(&found_modules, ml, link); + } + } + /* Don't try to run SYSUNINITs if we are unloaded due to a link error */ if (file->flags & LINKER_FILE_LINKED) { linker_file_sysuninit(file); @@ -423,9 +472,12 @@ linker_file_unload(linker_file_t file) TAILQ_REMOVE(&linker_files, file, link); lockmgr(&lock, LK_RELEASE, 0, curproc); - for (i = 0; i < file->ndeps; i++) - linker_file_unload(file->deps[i]); - free(file->deps, M_LINKER); + if (file->deps) { + for (i = 0; i < file->ndeps; i++) + linker_file_unload(file->deps[i]); + free(file->deps, M_LINKER); + file->deps = NULL; + } for (cp = STAILQ_FIRST(&file->common); cp; cp = STAILQ_FIRST(&file->common)) { @@ -434,7 +486,10 @@ linker_file_unload(linker_file_t file) } LINKER_UNLOAD(file); - free(file->filename, M_LINKER); + if (file->filename) { + free(file->filename, M_LINKER); + file->filename = NULL; + } kobj_delete((kobj_t) file, M_LINKER); out: @@ -468,7 +523,6 @@ linker_file_lookup_symbol(linker_file_t file, const char* name, int deps) { c_linker_sym_t sym; linker_symval_t symval; - linker_file_t lf; caddr_t address; size_t common_size = 0; int i; @@ -498,24 +552,6 @@ linker_file_lookup_symbol(linker_file_t file, const char* name, int deps) return address; } } - - /* If we have not found it in the dependencies, search globally */ - for (lf = TAILQ_FIRST(&linker_files); lf; lf = TAILQ_NEXT(lf, link)) { - /* But skip the current file if it's on the list */ - if (lf == file) - continue; - /* And skip the files we searched above */ - for (i = 0; i < file->ndeps; i++) - if (lf == file->deps[i]) - break; - if (i < file->ndeps) - continue; - address = linker_file_lookup_symbol(lf, name, 0); - if (address) { - KLD_DPF(SYM, ("linker_file_lookup_symbol: global value=%x\n", address)); - return address; - } - } } if (common_size > 0) { @@ -636,7 +672,8 @@ linker_ddb_symbol_values(c_linker_sym_t sym, linker_symval_t *symval) int kldload(struct proc* p, struct kldload_args* uap) { - char* filename = NULL, *modulename; + char* pathname, *realpath; + const char *filename; linker_file_t lf; int error = 0; @@ -648,30 +685,34 @@ kldload(struct proc* p, struct kldload_args* uap) if ((error = suser(p)) != 0) return error; - filename = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); - if ((error = copyinstr(SCARG(uap, file), filename, MAXPATHLEN, NULL)) != 0) + realpath = NULL; + pathname = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); + if ((error = copyinstr(SCARG(uap, file), pathname, MAXPATHLEN, NULL)) != 0) goto out; - /* Can't load more than one module with the same name */ - modulename = rindex(filename, '/'); - if (modulename == NULL) - modulename = filename; - else - modulename++; - if (linker_find_file_by_name(modulename)) { + realpath = linker_search_path(pathname); + if (realpath == NULL) { + error = ENOENT; + goto out; + } + /* Can't load more than one file with the same name */ + filename = linker_basename(realpath); + if (linker_find_file_by_name(filename)) { error = EEXIST; goto out; } - if ((error = linker_load_file(filename, &lf)) != 0) + if ((error = linker_load_file(realpath, &lf)) != 0) goto out; lf->userrefs++; p->p_retval[0] = lf->id; out: - if (filename) - free(filename, M_TEMP); + if (pathname) + free(pathname, M_TEMP); + if (realpath) + free(realpath, M_LINKER); return error; } @@ -691,7 +732,7 @@ kldunload(struct proc* p, struct kldunload_args* uap) if (lf) { KLD_DPF(FILE, ("kldunload: lf->userrefs=%d\n", lf->userrefs)); if (lf->userrefs == 0) { - printf("linkerunload: attempt to unload file that was loaded by the kernel\n"); + printf("kldunload: attempt to unload file that was loaded by the kernel\n"); error = EBUSY; goto out; } @@ -709,29 +750,28 @@ out: int kldfind(struct proc* p, struct kldfind_args* uap) { - char* filename = NULL, *modulename; + char* pathname; + const char *filename; linker_file_t lf; int error = 0; p->p_retval[0] = -1; - filename = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); - if ((error = copyinstr(SCARG(uap, file), filename, MAXPATHLEN, NULL)) != 0) + pathname = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); + if ((error = copyinstr(SCARG(uap, file), pathname, MAXPATHLEN, NULL)) != 0) goto out; - modulename = rindex(filename, '/'); - if (modulename == NULL) - modulename = filename; + filename = linker_basename(pathname); - lf = linker_find_file_by_name(modulename); + lf = linker_find_file_by_name(filename); if (lf) p->p_retval[0] = lf->id; else error = ENOENT; out: - if (filename) - free(filename, M_TEMP); + if (pathname) + free(pathname, M_TEMP); return error; } @@ -883,6 +923,27 @@ out: * Preloaded module support */ +static modlist_t +modlist_lookup(const char *name) +{ + modlist_t mod; + + for (mod = TAILQ_FIRST(&found_modules); mod; mod = TAILQ_NEXT(mod, link)) { + if (!strcmp(mod->name, name)) + return mod; + } + return NULL; +} + +/* + * This routine is cheap and nasty but will work for data pointers. + */ +static void * +linker_reloc_ptr(linker_file_t lf, void *offset) +{ + return lf->address + (uintptr_t)offset; +} + static void linker_preload(void* arg) { @@ -891,10 +952,20 @@ linker_preload(void* arg) char *modtype; linker_file_t lf; linker_class_t lc; - int error; + int error, mcount; struct linker_set *sysinits; - struct sysinit **sipp; - const moduledata_t *moddata; + linker_file_list_t loaded_files; + linker_file_list_t depended_files; + struct linker_set *deps; + struct mod_metadata *mp; + int i; + int resolves; + modlist_t mod; + + TAILQ_INIT(&loaded_files); + TAILQ_INIT(&depended_files); + TAILQ_INIT(&found_modules); + error = 0; modptr = NULL; while ((modptr = preload_search_next_name(modptr)) != NULL) { @@ -909,44 +980,158 @@ linker_preload(void* arg) continue; } printf("Preloaded %s \"%s\" at %p.\n", modtype, modname, modptr); - lf = linker_find_file_by_name(modname); - if (lf) { - lf->userrefs++; - continue; - } lf = NULL; for (lc = TAILQ_FIRST(&classes); lc; lc = TAILQ_NEXT(lc, link)) { - error = LINKER_LOAD_FILE(lc, modname, &lf); + error = LINKER_LINK_PRELOAD(lc, modname, &lf); if (error) { lf = NULL; break; } } - if (lf) { - lf->userrefs++; + if (lf) + TAILQ_INSERT_TAIL(&loaded_files, lf, loaded); + } + + /* + * First get a list of stuff in the kernel. + */ + deps = (struct linker_set*) + linker_file_lookup_symbol(linker_kernel_file, MDT_SETNAME, 0); + if (deps) { + for (i = 0; i < deps->ls_length; i++) { + mp = deps->ls_items[i]; + if (mp->md_type != MDT_VERSION) + continue; + modname = mp->md_cval; + if (modlist_lookup(modname) != NULL) { + printf("module %s already present!\n", modname); + /* XXX what can we do? this is a build error. :-( */ + continue; + } + mod = malloc(sizeof(struct modlist), M_LINKER, M_NOWAIT); + if (mod == NULL) + panic("no memory for module list"); + bzero(mod, sizeof(*mod)); + mod->container = linker_kernel_file; + mod->name = modname; + TAILQ_INSERT_TAIL(&found_modules, mod, link); + } + } - sysinits = (struct linker_set*) - linker_file_lookup_symbol(lf, "sysinit_set", 0); - if (sysinits) { - /* HACK ALERT! - * This is to set the sysinit moduledata so that the module - * can attach itself to the correct containing file. - * The sysinit could be run at *any* time. - */ - for (sipp = (struct sysinit **)sysinits->ls_items; *sipp; sipp++) { - if ((*sipp)->func == module_register_init) { - moddata = (*sipp)->udata; - error = module_register(moddata, lf); - if (error) - printf("Preloaded %s \"%s\" failed to register: %d\n", - modtype, modname, error); + /* + * this is a once-off kinky bubble sort + * resolve relocation dependency requirements + */ +restart: + for (lf = TAILQ_FIRST(&loaded_files); lf; lf = TAILQ_NEXT(lf, loaded)) { + deps = (struct linker_set*) + linker_file_lookup_symbol(lf, MDT_SETNAME, 0); + /* + * First, look to see if we would successfully link with this stuff. + */ + resolves = 1; /* unless we know otherwise */ + if (deps) { + for (i = 0; i < deps->ls_length; i++) { + mp = linker_reloc_ptr(lf, deps->ls_items[i]); + if (mp->md_type != MDT_DEPEND) + continue; + modname = linker_reloc_ptr(lf, mp->md_cval); + if (modlist_lookup(modname) == NULL) { + /* ok, the module isn't here yet, we are not finished */ + resolves = 0; + } + } + } + /* + * OK, if we found our modules, we can link. So, "provide" the + * modules inside and add it to the end of the link order list. + */ + if (resolves) { + if (deps) { + for (i = 0; i < deps->ls_length; i++) { + mp = linker_reloc_ptr(lf, deps->ls_items[i]); + if (mp->md_type != MDT_VERSION) + continue; + modname = linker_reloc_ptr(lf, mp->md_cval); + if (modlist_lookup(modname) != NULL) { + printf("module %s already present!\n", modname); + linker_file_unload(lf); + TAILQ_REMOVE(&loaded_files, lf, loaded); + goto restart; /* we changed the tailq next ptr */ } + mod = malloc(sizeof(struct modlist), M_LINKER, M_NOWAIT); + if (mod == NULL) + panic("no memory for module list"); + bzero(mod, sizeof(*mod)); + mod->container = lf; + mod->name = modname; + TAILQ_INSERT_TAIL(&found_modules, mod, link); } - sysinit_add((struct sysinit **)sysinits->ls_items); } - linker_file_register_sysctls(lf); + TAILQ_REMOVE(&loaded_files, lf, loaded); + TAILQ_INSERT_TAIL(&depended_files, lf, loaded); + /* + * Since we provided modules, we need to restart the sort so + * that the previous files that depend on us have a chance. + * Also, we've busted the tailq next pointer with the REMOVE. + */ + goto restart; } } + + /* + * At this point, we check to see what could not be resolved.. + */ + for (lf = TAILQ_FIRST(&loaded_files); lf; lf = TAILQ_NEXT(lf, loaded)) { + printf("KLD file %s is missing dependencies\n", lf->filename); + linker_file_unload(lf); + TAILQ_REMOVE(&loaded_files, lf, loaded); + } + + /* + * We made it. Finish off the linking in the order we determined. + */ + for (lf = TAILQ_FIRST(&depended_files); lf; lf = TAILQ_NEXT(lf, loaded)) { + if (linker_kernel_file) { + linker_kernel_file->refs++; + error = linker_file_add_dependancy(lf, linker_kernel_file); + if (error) + panic("cannot add dependency"); + } + lf->userrefs++; /* so we can (try to) kldunload it */ + deps = (struct linker_set*) + linker_file_lookup_symbol(lf, MDT_SETNAME, 0); + if (deps) { + for (i = 0; i < deps->ls_length; i++) { + mp = linker_reloc_ptr(lf, deps->ls_items[i]); + if (mp->md_type != MDT_DEPEND) + continue; + modname = linker_reloc_ptr(lf, mp->md_cval); + mod = modlist_lookup(modname); + mod->container->refs++; + error = linker_file_add_dependancy(lf, mod->container); + if (error) + panic("cannot add dependency"); + } + } + + /* Now do relocation etc using the symbol search paths established by the dependencies */ + error = LINKER_LINK_PRELOAD_FINISH(lf); + if (error) { + printf("KLD file %s - could not finalize loading\n", lf->filename); + linker_file_unload(lf); + continue; + } + + mcount = linker_file_register_modules(lf); + sysinits = (struct linker_set*) + linker_file_lookup_symbol(lf, "sysinit_set", 0); + if (sysinits) + sysinit_add((struct sysinit **)sysinits->ls_items); + linker_file_register_sysctls(lf); + lf->flags |= LINKER_FILE_LINKED; + } + /* woohoo! we made it! */ } SYSINIT(preload, SI_SUB_KLD, SI_ORDER_MIDDLE, linker_preload, 0); @@ -971,46 +1156,63 @@ static char linker_path[MAXPATHLEN] = "/;/boot/;/modules/"; SYSCTL_STRING(_kern, OID_AUTO, module_path, CTLFLAG_RW, linker_path, sizeof(linker_path), "module load search path"); -char * +static char *linker_ext_list[] = { + ".ko", + "", + NULL +}; + +static char * linker_search_path(const char *name) { struct nameidata nd; struct proc *p = curproc; /* XXX */ - char *cp, *ep, *result; - int error; + char *cp, *ep, *result, **cpp; + int error, extlen, len; enum vtype type; /* qualified at all? */ if (index(name, '/')) return(linker_strdup(name)); + extlen = 0; + for (cpp = linker_ext_list; *cpp; cpp++) { + len = strlen(*cpp); + if (len > extlen) + extlen = len; + } + extlen++; /* trailing '\0' */ + /* traverse the linker path */ cp = linker_path; + len = strlen(name); for (;;) { /* find the end of this component */ for (ep = cp; (*ep != 0) && (*ep != ';'); ep++) ; - result = malloc((strlen(name) + (ep - cp) + 1), M_LINKER, M_WAITOK); + result = malloc((len + (ep - cp) + extlen), M_LINKER, M_WAITOK); if (result == NULL) /* actually ENOMEM */ return(NULL); + for (cpp = linker_ext_list; *cpp; cpp++) { + strncpy(result, cp, ep - cp); + strcpy(result + (ep - cp), name); + strcat(result, *cpp); - strncpy(result, cp, ep - cp); - strcpy(result + (ep - cp), name); - - /* - * Attempt to open the file, and return the path if we succeed and it's - * a regular file. - */ - NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, result, p); - error = vn_open(&nd, FREAD, 0); - if (error == 0) { - NDFREE(&nd, NDF_ONLY_PNBUF); - type = nd.ni_vp->v_type; - VOP_UNLOCK(nd.ni_vp, 0, p); - vn_close(nd.ni_vp, FREAD, p->p_ucred, p); - if (type == VREG) - return(result); + /* + * Attempt to open the file, and return the path if we succeed + * and it's a regular file. + */ + NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, result, p); + error = vn_open(&nd, FREAD, 0); + if (error == 0) { + NDFREE(&nd, NDF_ONLY_PNBUF); + type = nd.ni_vp->v_type; + VOP_UNLOCK(nd.ni_vp, 0, p); + vn_close(nd.ni_vp, FREAD, p->p_ucred, p); + if (type == VREG) + return(result); + } } free(result, M_LINKER); @@ -1020,3 +1222,151 @@ linker_search_path(const char *name) } return(NULL); } + +static const char * +linker_basename(const char* path) +{ + const char *filename; + + filename = rindex(path, '/'); + if (filename == NULL) + return path; + if (filename[1]) + filename++; + return filename; +} + +/* + * Find a file which contains given module and load it, + * if "parent" is not NULL, register a reference to it. + */ +static int +linker_load_module(const char *modname, struct linker_file *parent) +{ + linker_file_t lfdep; + const char *filename; + char *pathname; + int error; + + /* + * There will be a system to look up or guess a file name from + * a module name. + * For now we just try to load a file with the same name. + */ + pathname = linker_search_path(modname); + if (pathname == NULL) + return ENOENT; + + /* Can't load more than one file with the same basename */ + filename = linker_basename(pathname); + if (linker_find_file_by_name(filename)) { + error = EEXIST; + goto out; + } + + do { + error = linker_load_file(pathname, &lfdep); + if (error) + break; + if (parent) { + error = linker_file_add_dependancy(parent, lfdep); + if (error) + break; + } + } while(0); +out: + if (pathname) + free(pathname, M_LINKER); + return error; +} + +/* + * This routine is responsible for finding dependencies of userland + * initiated kldload(2)'s of files. + */ +int +linker_load_dependancies(linker_file_t lf) +{ + linker_file_t lfdep; + struct linker_set *deps; + struct mod_metadata *mp, *nmp; + modlist_t mod; + char *modname, *nmodname; + int i, j, error = 0; + + /* + * All files are dependant on /kernel. + */ + if (linker_kernel_file) { + linker_kernel_file->refs++; + error = linker_file_add_dependancy(lf, linker_kernel_file); + if (error) + return error; + } + + deps = (struct linker_set*) + linker_file_lookup_symbol(lf, MDT_SETNAME, 0); + if (deps != NULL) { + for (i = 0; i < deps->ls_length; i++) { + mp = linker_reloc_ptr(lf, deps->ls_items[i]); + if (mp->md_type != MDT_VERSION) + continue; + modname = linker_reloc_ptr(lf, mp->md_cval); + if (modlist_lookup(modname) != NULL) { + printf("module %s already present!\n", modname); + return EEXIST; + } + } + } + if (deps != NULL) { + for (i = 0; i < deps->ls_length; i++) { + mp = linker_reloc_ptr(lf, deps->ls_items[i]); + if (mp->md_type != MDT_DEPEND) + continue; + modname = linker_reloc_ptr(lf, mp->md_cval); + nmodname = NULL; + for (j = 0; j < deps->ls_length; j++) { + nmp = linker_reloc_ptr(lf, deps->ls_items[j]); + if (nmp->md_type != MDT_VERSION) + continue; + nmodname = linker_reloc_ptr(lf, nmp->md_cval); + if (strcmp(modname, nmodname) == 0) + break; + } + if (j < deps->ls_length) /* early exit, it's a self reference */ + continue; + mod = modlist_lookup(modname); + if (mod) { /* woohoo, it's loaded already */ + lfdep = mod->container; + lfdep->refs++; + error = linker_file_add_dependancy(lf, lfdep); + if (error) + break; + continue; + } + error = linker_load_module(modname, lf); + if (error) { + printf("KLD %s: depends on %s - not available\n", + lf->filename, modname); + break; + } + } + + } + if (error == 0 && deps) { + for (i = 0; i < deps->ls_length; i++) { + mp = linker_reloc_ptr(lf, deps->ls_items[i]); + if (mp->md_type != MDT_VERSION) + continue; + modname = linker_reloc_ptr(lf, mp->md_cval); + mod = malloc(sizeof(struct modlist), M_LINKER, M_NOWAIT); + if (mod == NULL) + panic("no memory for module list"); + bzero(mod, sizeof(*mod)); + mod->container = lf; + mod->name = modname; + TAILQ_INSERT_TAIL(&found_modules, mod, link); + } + } + return error; +} diff --git a/sys/kern/kern_module.c b/sys/kern/kern_module.c index e451b97..46c3d14 100644 --- a/sys/kern/kern_module.c +++ b/sys/kern/kern_module.c @@ -37,7 +37,7 @@ #include <sys/linker.h> #include <sys/proc.h> -#define M_MODULE M_TEMP /* XXX */ +MALLOC_DEFINE(M_MODULE, "module", "module data structures"); typedef TAILQ_HEAD(, module) modulelist_t; struct module { @@ -93,19 +93,8 @@ module_register_init(const void *arg) module_t mod; mod = module_lookupbyname(data->name); - if (mod == NULL) { -#if 0 + if (mod == NULL) panic("module_register_init: module named %s not found\n", data->name); -#else - /* temporary kludge until kernel `file' attachment registers modules */ - error = module_register(data, linker_kernel_file); - if (error) - panic("module_register_init: register of module failed! %d", error); - mod = module_lookupbyname(data->name); - if (mod == NULL) - panic("module_register_init: module STILL not found!"); -#endif - } error = MOD_EVENT(mod, MOD_LOAD); if (error) { MOD_EVENT(mod, MOD_UNLOAD); @@ -141,8 +130,6 @@ module_register(const moduledata_t *data, linker_file_t container) bzero(&newmod->data, sizeof(newmod->data)); TAILQ_INSERT_TAIL(&modules, newmod, link); - if (container == NULL) - container = linker_current_file; if (container) TAILQ_INSERT_TAIL(&container->modules, newmod, flink); newmod->file = container; diff --git a/sys/kern/link_aout.c b/sys/kern/link_aout.c index f9b55e5..652b619 100644 --- a/sys/kern/link_aout.c +++ b/sys/kern/link_aout.c @@ -60,11 +60,11 @@ typedef struct aout_file { struct _dynamic* dynamic; /* Symbol table etc. */ } *aout_file_t; -static int link_aout_load_module(linker_class_t lc, - const char*, linker_file_t*); - -static int link_aout_load_file(const char*, linker_file_t*); +static int link_aout_link_preload(linker_class_t lc, + const char* modname, linker_file_t*); +static int link_aout_link_preload_finish(linker_file_t); +static int link_aout_load_file(linker_class_t lc, const char*, linker_file_t*); static int link_aout_lookup_symbol(linker_file_t, const char*, c_linker_sym_t*); static int link_aout_symbol_values(linker_file_t file, c_linker_sym_t sym, @@ -72,14 +72,16 @@ static int link_aout_symbol_values(linker_file_t file, c_linker_sym_t sym, static int link_aout_search_symbol(linker_file_t lf, caddr_t value, c_linker_sym_t* sym, long* diffp); static void link_aout_unload_file(linker_file_t); -static void link_aout_unload_module(linker_file_t); +static void link_aout_unload_preload(linker_file_t); static kobj_method_t link_aout_methods[] = { KOBJMETHOD(linker_lookup_symbol, link_aout_lookup_symbol), KOBJMETHOD(linker_symbol_values, link_aout_symbol_values), KOBJMETHOD(linker_search_symbol, link_aout_search_symbol), KOBJMETHOD(linker_unload, link_aout_unload_file), - KOBJMETHOD(linker_load_file, link_aout_load_module), + KOBJMETHOD(linker_load_file, link_aout_load_file), + KOBJMETHOD(linker_link_preload, link_aout_link_preload), + KOBJMETHOD(linker_link_preload_finish, link_aout_link_preload_finish), { 0, 0 } }; @@ -87,7 +89,6 @@ static struct linker_class link_aout_class = { "a.out", link_aout_methods, sizeof(struct aout_file) }; -static int load_dependancies(aout_file_t af); static int relocate_file(aout_file_t af); /* @@ -117,8 +118,6 @@ link_aout_init(void* arg) af->dynamic = dp; linker_kernel_file->address = (caddr_t) KERNBASE; linker_kernel_file->size = -(long)linker_kernel_file->address; - linker_current_file = linker_kernel_file; - linker_kernel_file->flags |= LINKER_FILE_LINKED; } #endif } @@ -126,21 +125,20 @@ link_aout_init(void* arg) SYSINIT(link_aout, SI_SUB_KLD, SI_ORDER_THIRD, link_aout_init, 0); static int -link_aout_load_module(linker_class_t lc, - const char* filename, linker_file_t* result) +link_aout_link_preload(linker_class_t lc, + const char* filename, linker_file_t* result) { caddr_t modptr, baseptr; char *type; struct exec *ehdr; aout_file_t af; linker_file_t lf; - int error; /* Look to see if we have the module preloaded. */ - if ((modptr = preload_search_by_name(filename)) == NULL) - return(link_aout_load_file(filename, result)); + modptr = preload_search_by_name(filename); + if (modptr == NULL) + return ENOENT; - /* It's preloaded, check we can handle it and collect information. */ if (((type = (char *)preload_search_info(modptr, MODINFO_TYPE)) == NULL) || strcmp(type, "a.out module") || ((baseptr = preload_search_info(modptr, MODINFO_ADDR)) == NULL) || @@ -155,6 +153,7 @@ link_aout_load_module(linker_class_t lc, af = (aout_file_t) lf; /* Looks like we can handle this one */ + filename = preload_search_info(modptr, MODINFO_NAME); af->preloaded = 1; af->address = baseptr; @@ -169,20 +168,27 @@ link_aout_load_module(linker_class_t lc, lf->address = af->address; lf->size = ehdr->a_text + ehdr->a_data + ehdr->a_bss; + *result = lf; + return(0); +} - /* Try to load dependancies */ - if (((error = load_dependancies(af)) != 0) || - ((error = relocate_file(af)) != 0)) { +static int +link_aout_link_preload_finish(linker_file_t lf) +{ + aout_file_t af; + int error; + + af = (aout_file_t) lf; + error = relocate_file(af); + if (error) { linker_file_unload(lf); return(error); } - lf->flags |= LINKER_FILE_LINKED; - *result = lf; return(0); } static int -link_aout_load_file(const char* filename, linker_file_t* result) +link_aout_load_file(linker_class_t lc, const char* filename, linker_file_t* result) { struct nameidata nd; struct proc* p = curproc; /* XXX */ @@ -191,14 +197,9 @@ link_aout_load_file(const char* filename, linker_file_t* result) struct exec header; aout_file_t af; linker_file_t lf = 0; - char *pathname; - pathname = linker_search_path(filename); - if (pathname == NULL) - return ENOENT; - NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, pathname, p); + NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, filename, p); error = vn_open(&nd, FREAD, 0); - free(pathname, M_LINKER); if (error) return error; NDFREE(&nd, NDF_ONLY_PNBUF); @@ -251,12 +252,13 @@ link_aout_load_file(const char* filename, linker_file_t* result) lf->address = af->address; lf->size = header.a_text + header.a_data + header.a_bss; - if ((error = load_dependancies(af)) != 0 - || (error = relocate_file(af)) != 0) { + error = linker_load_dependancies(lf); + if (error) + goto out; + error = relocate_file(af); + if (error) goto out; - } - lf->flags |= LINKER_FILE_LINKED; *result = lf; out: @@ -274,7 +276,7 @@ link_aout_unload_file(linker_file_t file) aout_file_t af = (aout_file_t) file; if (af->preloaded) { - link_aout_unload_module(file); + link_aout_unload_preload(file); return; } @@ -283,56 +285,12 @@ link_aout_unload_file(linker_file_t file) } static void -link_aout_unload_module(linker_file_t file) +link_aout_unload_preload(linker_file_t file) { if (file->filename) preload_delete_name(file->filename); } -#define AOUT_RELOC(af, type, off) (type*) ((af)->address + (off)) - -static int -load_dependancies(aout_file_t af) -{ - linker_file_t lfdep; - long off; - struct sod* sodp; - char* name; - char* filename = 0; - int error = 0; - - /* - * All files are dependant on /kernel. - */ - if (linker_kernel_file) { - linker_kernel_file->refs++; - linker_file_add_dependancy(&af->lf, linker_kernel_file); - } - - off = LD_NEED(af->dynamic); - - /* - * Load the dependancies. - */ - while (off != 0) { - sodp = AOUT_RELOC(af, struct sod, off); - name = AOUT_RELOC(af, char, sodp->sod_name); - - error = linker_load_file(name, &lfdep); - if (error) - goto out; - error = linker_file_add_dependancy(&af->lf, lfdep); - if (error) - goto out; - off = sodp->sod_next; - } - -out: - if (filename) - free(filename, M_TEMP); - return error; -} - /* * XXX i386 dependant. */ @@ -340,6 +298,7 @@ static long read_relocation(struct relocation_info* r, char* addr) { int length = r->r_length; + if (length == 0) return *(u_char*) addr; else if (length == 1) @@ -355,6 +314,7 @@ static void write_relocation(struct relocation_info* r, char* addr, long value) { int length = r->r_length; + if (length == 0) *(u_char*) addr = value; else if (length == 1) @@ -365,6 +325,8 @@ write_relocation(struct relocation_info* r, char* addr, long value) printf("link_aout: unsupported relocation size %d\n", r->r_length); } +#define AOUT_RELOC(af, type, off) (type*) ((af)->address + (off)) + static int relocate_file(aout_file_t af) { diff --git a/sys/kern/link_elf.c b/sys/kern/link_elf.c index f7c0e2a..1f98c4c 100644 --- a/sys/kern/link_elf.c +++ b/sys/kern/link_elf.c @@ -91,9 +91,10 @@ typedef struct elf_file { #endif } *elf_file_t; -static int link_elf_load_module(linker_class_t cls, - const char*, linker_file_t*); -static int link_elf_load_file(const char*, linker_file_t*); +static int link_elf_link_preload(linker_class_t cls, + const char*, linker_file_t*); +static int link_elf_link_preload_finish(linker_file_t); +static int link_elf_load_file(linker_class_t, const char*, linker_file_t*); static int link_elf_lookup_symbol(linker_file_t, const char*, c_linker_sym_t*); static int link_elf_symbol_values(linker_file_t, c_linker_sym_t, linker_symval_t*); @@ -101,14 +102,16 @@ static int link_elf_search_symbol(linker_file_t, caddr_t value, c_linker_sym_t* sym, long* diffp); static void link_elf_unload_file(linker_file_t); -static void link_elf_unload_module(linker_file_t); +static void link_elf_unload_preload(linker_file_t); static kobj_method_t link_elf_methods[] = { KOBJMETHOD(linker_lookup_symbol, link_elf_lookup_symbol), KOBJMETHOD(linker_symbol_values, link_elf_symbol_values), KOBJMETHOD(linker_search_symbol, link_elf_search_symbol), KOBJMETHOD(linker_unload, link_elf_unload_file), - KOBJMETHOD(linker_load_file, link_elf_load_module), + KOBJMETHOD(linker_load_file, link_elf_load_file), + KOBJMETHOD(linker_link_preload, link_elf_link_preload), + KOBJMETHOD(linker_link_preload_finish, link_elf_link_preload_finish), { 0, 0 } }; @@ -122,9 +125,8 @@ static struct linker_class link_elf_class = { }; static int parse_dynamic(elf_file_t ef); -static int load_dependancies(elf_file_t ef); static int relocate_file(elf_file_t ef); -static int parse_module_symbols(elf_file_t ef); +static int link_elf_preload_parse_symbols(elf_file_t ef); #ifdef DDB @@ -176,6 +178,7 @@ link_elf_init(void* arg) panic("link_elf_init: Can't create linker structures for kernel"); ef = (elf_file_t) linker_kernel_file; + ef->preloaded = 1; ef->address = 0; #ifdef SPARSE_MAPPING ef->object = 0; @@ -195,9 +198,7 @@ link_elf_init(void* arg) if (sizeptr) linker_kernel_file->size = *(size_t *)sizeptr; } - (void)parse_module_symbols(ef); - linker_current_file = linker_kernel_file; - linker_kernel_file->flags |= LINKER_FILE_LINKED; + (void)link_elf_preload_parse_symbols(ef); #ifdef DDB ef->gdb.l_addr = linker_kernel_file->address; @@ -220,7 +221,7 @@ link_elf_init(void* arg) SYSINIT(link_elf, SI_SUB_KLD, SI_ORDER_SECOND, link_elf_init, 0); static int -parse_module_symbols(elf_file_t ef) +link_elf_preload_parse_symbols(elf_file_t ef) { caddr_t pointer; caddr_t ssym, esym, base; @@ -400,8 +401,8 @@ link_elf_delete_gdb(struct link_map *l) #endif /* DDB */ static int -link_elf_load_module(linker_class_t cls, - const char *filename, linker_file_t *result) +link_elf_link_preload(linker_class_t cls, + const char* filename, linker_file_t *result) { caddr_t modptr, baseptr, sizeptr, dynptr; char *type; @@ -410,12 +411,11 @@ link_elf_load_module(linker_class_t cls, int error; vm_offset_t dp; - /* Look to see if we have the module preloaded */ + /* Look to see if we have the file preloaded */ modptr = preload_search_by_name(filename); if (modptr == NULL) - return (link_elf_load_file(filename, result)); + return ENOENT; - /* It's preloaded, check we can handle it and collect information */ type = (char *)preload_search_info(modptr, MODINFO_TYPE); baseptr = preload_search_info(modptr, MODINFO_ADDR); sizeptr = preload_search_info(modptr, MODINFO_SIZE); @@ -439,7 +439,6 @@ link_elf_load_module(linker_class_t cls, #endif dp = (vm_offset_t)ef->address + *(vm_offset_t *)dynptr; ef->dynamic = (Elf_Dyn *)dp; - lf->address = ef->address; lf->size = *(size_t *)sizeptr; @@ -448,34 +447,46 @@ link_elf_load_module(linker_class_t cls, linker_file_unload(lf); return error; } - error = load_dependancies(ef); - if (error) { - linker_file_unload(lf); - return error; + *result = lf; + return (0); +} + +static int +link_elf_link_preload_finish(linker_file_t lf) +{ + elf_file_t ef; + int error; + + ef = (elf_file_t) lf; +#if 0 /* this will be more trouble than it's worth for now */ + for (dp = ef->dynamic; dp->d_tag != DT_NULL; dp++) { + if (dp->d_tag != DT_NEEDED) + continue; + modname = ef->strtab + dp->d_un.d_val; + error = linker_load_module(modname, lf); + if (error) + goto out; } +#endif error = relocate_file(ef); - if (error) { - linker_file_unload(lf); + if (error) return error; - } - (void)parse_module_symbols(ef); - lf->flags |= LINKER_FILE_LINKED; + (void)link_elf_preload_parse_symbols(ef); #ifdef DDB GDB_STATE(RT_ADD); ef->gdb.l_addr = lf->address; - ef->gdb.l_name = filename; + ef->gdb.l_name = lf->filename; ef->gdb.l_ld = ef->dynamic; link_elf_add_gdb(&ef->gdb); GDB_STATE(RT_CONSISTENT); #endif - *result = lf; return (0); } static int -link_elf_load_file(const char* filename, linker_file_t* result) +link_elf_load_file(linker_class_t cls, const char* filename, linker_file_t* result) { struct nameidata nd; struct proc* p = curproc; /* XXX */ @@ -497,7 +508,6 @@ link_elf_load_file(const char* filename, linker_file_t* result) int resid; elf_file_t ef; linker_file_t lf; - char *pathname; Elf_Shdr *shdr; int symtabindex; int symstrindex; @@ -507,13 +517,8 @@ link_elf_load_file(const char* filename, linker_file_t* result) shdr = NULL; lf = NULL; - pathname = linker_search_path(filename); - if (pathname == NULL) - return ENOENT; - - NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, pathname, p); + NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, filename, p); error = vn_open(&nd, FREAD, 0); - free(pathname, M_LINKER); if (error) return error; NDFREE(&nd, NDF_ONLY_PNBUF); @@ -688,9 +693,19 @@ link_elf_load_file(const char* filename, linker_file_t* result) error = parse_dynamic(ef); if (error) goto out; - error = load_dependancies(ef); + error = linker_load_dependancies(lf); if (error) goto out; +#if 0 /* this will be more trouble than it's worth for now */ + for (dp = ef->dynamic; dp->d_tag != DT_NULL; dp++) { + if (dp->d_tag != DT_NEEDED) + continue; + modname = ef->strtab + dp->d_un.d_val; + error = linker_load_module(modname, lf); + if (error) + goto out; + } +#endif error = relocate_file(ef); if (error) goto out; @@ -746,12 +761,10 @@ link_elf_load_file(const char* filename, linker_file_t* result) ef->ddbstrcnt = strcnt; ef->ddbstrtab = ef->strbase; - lf->flags |= LINKER_FILE_LINKED; - #ifdef DDB GDB_STATE(RT_ADD); ef->gdb.l_addr = lf->address; - ef->gdb.l_name = linker_search_path(filename); + ef->gdb.l_name = filename; ef->gdb.l_ld = ef->dynamic; link_elf_add_gdb(&ef->gdb); GDB_STATE(RT_CONSISTENT); @@ -784,13 +797,11 @@ link_elf_unload_file(linker_file_t file) GDB_STATE(RT_DELETE); link_elf_delete_gdb(&ef->gdb); GDB_STATE(RT_CONSISTENT); - /* The strange cast is to quieten a 'discarding const' warning. */ - free((caddr_t) (uintptr_t) ef->gdb.l_name, M_LINKER); } #endif if (ef->preloaded) { - link_elf_unload_module(file); + link_elf_unload_preload(file); return; } #ifdef SPARSE_MAPPING @@ -811,45 +822,12 @@ link_elf_unload_file(linker_file_t file) } static void -link_elf_unload_module(linker_file_t file) +link_elf_unload_preload(linker_file_t file) { if (file->filename) preload_delete_name(file->filename); } -static int -load_dependancies(elf_file_t ef) -{ - linker_file_t lfdep; - char* name; - const Elf_Dyn *dp; - int error = 0; - - /* - * All files are dependant on /kernel. - */ - if (linker_kernel_file) { - linker_kernel_file->refs++; - linker_file_add_dependancy(&ef->lf, linker_kernel_file); - } - - for (dp = ef->dynamic; dp->d_tag != DT_NULL; dp++) { - if (dp->d_tag == DT_NEEDED) { - name = ef->strtab + dp->d_un.d_val; - - error = linker_load_file(name, &lfdep); - if (error) - goto out; - error = linker_file_add_dependancy(&ef->lf, lfdep); - if (error) - goto out; - } - } - -out: - return error; -} - static const char * symbol_name(elf_file_t ef, Elf_Word r_info) { diff --git a/sys/kern/link_elf_obj.c b/sys/kern/link_elf_obj.c index f7c0e2a..1f98c4c 100644 --- a/sys/kern/link_elf_obj.c +++ b/sys/kern/link_elf_obj.c @@ -91,9 +91,10 @@ typedef struct elf_file { #endif } *elf_file_t; -static int link_elf_load_module(linker_class_t cls, - const char*, linker_file_t*); -static int link_elf_load_file(const char*, linker_file_t*); +static int link_elf_link_preload(linker_class_t cls, + const char*, linker_file_t*); +static int link_elf_link_preload_finish(linker_file_t); +static int link_elf_load_file(linker_class_t, const char*, linker_file_t*); static int link_elf_lookup_symbol(linker_file_t, const char*, c_linker_sym_t*); static int link_elf_symbol_values(linker_file_t, c_linker_sym_t, linker_symval_t*); @@ -101,14 +102,16 @@ static int link_elf_search_symbol(linker_file_t, caddr_t value, c_linker_sym_t* sym, long* diffp); static void link_elf_unload_file(linker_file_t); -static void link_elf_unload_module(linker_file_t); +static void link_elf_unload_preload(linker_file_t); static kobj_method_t link_elf_methods[] = { KOBJMETHOD(linker_lookup_symbol, link_elf_lookup_symbol), KOBJMETHOD(linker_symbol_values, link_elf_symbol_values), KOBJMETHOD(linker_search_symbol, link_elf_search_symbol), KOBJMETHOD(linker_unload, link_elf_unload_file), - KOBJMETHOD(linker_load_file, link_elf_load_module), + KOBJMETHOD(linker_load_file, link_elf_load_file), + KOBJMETHOD(linker_link_preload, link_elf_link_preload), + KOBJMETHOD(linker_link_preload_finish, link_elf_link_preload_finish), { 0, 0 } }; @@ -122,9 +125,8 @@ static struct linker_class link_elf_class = { }; static int parse_dynamic(elf_file_t ef); -static int load_dependancies(elf_file_t ef); static int relocate_file(elf_file_t ef); -static int parse_module_symbols(elf_file_t ef); +static int link_elf_preload_parse_symbols(elf_file_t ef); #ifdef DDB @@ -176,6 +178,7 @@ link_elf_init(void* arg) panic("link_elf_init: Can't create linker structures for kernel"); ef = (elf_file_t) linker_kernel_file; + ef->preloaded = 1; ef->address = 0; #ifdef SPARSE_MAPPING ef->object = 0; @@ -195,9 +198,7 @@ link_elf_init(void* arg) if (sizeptr) linker_kernel_file->size = *(size_t *)sizeptr; } - (void)parse_module_symbols(ef); - linker_current_file = linker_kernel_file; - linker_kernel_file->flags |= LINKER_FILE_LINKED; + (void)link_elf_preload_parse_symbols(ef); #ifdef DDB ef->gdb.l_addr = linker_kernel_file->address; @@ -220,7 +221,7 @@ link_elf_init(void* arg) SYSINIT(link_elf, SI_SUB_KLD, SI_ORDER_SECOND, link_elf_init, 0); static int -parse_module_symbols(elf_file_t ef) +link_elf_preload_parse_symbols(elf_file_t ef) { caddr_t pointer; caddr_t ssym, esym, base; @@ -400,8 +401,8 @@ link_elf_delete_gdb(struct link_map *l) #endif /* DDB */ static int -link_elf_load_module(linker_class_t cls, - const char *filename, linker_file_t *result) +link_elf_link_preload(linker_class_t cls, + const char* filename, linker_file_t *result) { caddr_t modptr, baseptr, sizeptr, dynptr; char *type; @@ -410,12 +411,11 @@ link_elf_load_module(linker_class_t cls, int error; vm_offset_t dp; - /* Look to see if we have the module preloaded */ + /* Look to see if we have the file preloaded */ modptr = preload_search_by_name(filename); if (modptr == NULL) - return (link_elf_load_file(filename, result)); + return ENOENT; - /* It's preloaded, check we can handle it and collect information */ type = (char *)preload_search_info(modptr, MODINFO_TYPE); baseptr = preload_search_info(modptr, MODINFO_ADDR); sizeptr = preload_search_info(modptr, MODINFO_SIZE); @@ -439,7 +439,6 @@ link_elf_load_module(linker_class_t cls, #endif dp = (vm_offset_t)ef->address + *(vm_offset_t *)dynptr; ef->dynamic = (Elf_Dyn *)dp; - lf->address = ef->address; lf->size = *(size_t *)sizeptr; @@ -448,34 +447,46 @@ link_elf_load_module(linker_class_t cls, linker_file_unload(lf); return error; } - error = load_dependancies(ef); - if (error) { - linker_file_unload(lf); - return error; + *result = lf; + return (0); +} + +static int +link_elf_link_preload_finish(linker_file_t lf) +{ + elf_file_t ef; + int error; + + ef = (elf_file_t) lf; +#if 0 /* this will be more trouble than it's worth for now */ + for (dp = ef->dynamic; dp->d_tag != DT_NULL; dp++) { + if (dp->d_tag != DT_NEEDED) + continue; + modname = ef->strtab + dp->d_un.d_val; + error = linker_load_module(modname, lf); + if (error) + goto out; } +#endif error = relocate_file(ef); - if (error) { - linker_file_unload(lf); + if (error) return error; - } - (void)parse_module_symbols(ef); - lf->flags |= LINKER_FILE_LINKED; + (void)link_elf_preload_parse_symbols(ef); #ifdef DDB GDB_STATE(RT_ADD); ef->gdb.l_addr = lf->address; - ef->gdb.l_name = filename; + ef->gdb.l_name = lf->filename; ef->gdb.l_ld = ef->dynamic; link_elf_add_gdb(&ef->gdb); GDB_STATE(RT_CONSISTENT); #endif - *result = lf; return (0); } static int -link_elf_load_file(const char* filename, linker_file_t* result) +link_elf_load_file(linker_class_t cls, const char* filename, linker_file_t* result) { struct nameidata nd; struct proc* p = curproc; /* XXX */ @@ -497,7 +508,6 @@ link_elf_load_file(const char* filename, linker_file_t* result) int resid; elf_file_t ef; linker_file_t lf; - char *pathname; Elf_Shdr *shdr; int symtabindex; int symstrindex; @@ -507,13 +517,8 @@ link_elf_load_file(const char* filename, linker_file_t* result) shdr = NULL; lf = NULL; - pathname = linker_search_path(filename); - if (pathname == NULL) - return ENOENT; - - NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, pathname, p); + NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, filename, p); error = vn_open(&nd, FREAD, 0); - free(pathname, M_LINKER); if (error) return error; NDFREE(&nd, NDF_ONLY_PNBUF); @@ -688,9 +693,19 @@ link_elf_load_file(const char* filename, linker_file_t* result) error = parse_dynamic(ef); if (error) goto out; - error = load_dependancies(ef); + error = linker_load_dependancies(lf); if (error) goto out; +#if 0 /* this will be more trouble than it's worth for now */ + for (dp = ef->dynamic; dp->d_tag != DT_NULL; dp++) { + if (dp->d_tag != DT_NEEDED) + continue; + modname = ef->strtab + dp->d_un.d_val; + error = linker_load_module(modname, lf); + if (error) + goto out; + } +#endif error = relocate_file(ef); if (error) goto out; @@ -746,12 +761,10 @@ link_elf_load_file(const char* filename, linker_file_t* result) ef->ddbstrcnt = strcnt; ef->ddbstrtab = ef->strbase; - lf->flags |= LINKER_FILE_LINKED; - #ifdef DDB GDB_STATE(RT_ADD); ef->gdb.l_addr = lf->address; - ef->gdb.l_name = linker_search_path(filename); + ef->gdb.l_name = filename; ef->gdb.l_ld = ef->dynamic; link_elf_add_gdb(&ef->gdb); GDB_STATE(RT_CONSISTENT); @@ -784,13 +797,11 @@ link_elf_unload_file(linker_file_t file) GDB_STATE(RT_DELETE); link_elf_delete_gdb(&ef->gdb); GDB_STATE(RT_CONSISTENT); - /* The strange cast is to quieten a 'discarding const' warning. */ - free((caddr_t) (uintptr_t) ef->gdb.l_name, M_LINKER); } #endif if (ef->preloaded) { - link_elf_unload_module(file); + link_elf_unload_preload(file); return; } #ifdef SPARSE_MAPPING @@ -811,45 +822,12 @@ link_elf_unload_file(linker_file_t file) } static void -link_elf_unload_module(linker_file_t file) +link_elf_unload_preload(linker_file_t file) { if (file->filename) preload_delete_name(file->filename); } -static int -load_dependancies(elf_file_t ef) -{ - linker_file_t lfdep; - char* name; - const Elf_Dyn *dp; - int error = 0; - - /* - * All files are dependant on /kernel. - */ - if (linker_kernel_file) { - linker_kernel_file->refs++; - linker_file_add_dependancy(&ef->lf, linker_kernel_file); - } - - for (dp = ef->dynamic; dp->d_tag != DT_NULL; dp++) { - if (dp->d_tag == DT_NEEDED) { - name = ef->strtab + dp->d_un.d_val; - - error = linker_load_file(name, &lfdep); - if (error) - goto out; - error = linker_file_add_dependancy(&ef->lf, lfdep); - if (error) - goto out; - } - } - -out: - return error; -} - static const char * symbol_name(elf_file_t ef, Elf_Word r_info) { diff --git a/sys/kern/linker_if.m b/sys/kern/linker_if.m index e354d12..5f6f239 100644 --- a/sys/kern/linker_if.m +++ b/sys/kern/linker_if.m @@ -73,3 +73,11 @@ STATICMETHOD int load_file { const char* filename; linker_file_t* result; }; +STATICMETHOD int link_preload { + linker_class_t cls; + const char* filename; + linker_file_t* result; +}; +STATICMETHOD int link_preload_finish { + linker_file_t file; +}; diff --git a/sys/sys/linker.h b/sys/sys/linker.h index 5ca1c6c..60c47b5 100644 --- a/sys/sys/linker.h +++ b/sys/sys/linker.h @@ -77,6 +77,7 @@ struct linker_file { linker_file_t* deps; /* list of dependancies */ STAILQ_HEAD(, common_symbol) common; /* list of common symbols */ TAILQ_HEAD(, module) modules; /* modules in this file */ + TAILQ_ENTRY(linker_file) loaded; /* preload dependency support */ }; /* @@ -91,12 +92,6 @@ struct linker_class { }; /* - * The file which is currently loading. Used to register modules with - * the files which contain them. - */ -extern linker_file_t linker_current_file; - -/* * The "file" for the kernel. */ extern linker_file_t linker_kernel_file; @@ -144,10 +139,10 @@ caddr_t linker_file_lookup_symbol(linker_file_t file, const char* name, int deps); /* - * Search the linker path for the module. Return the full pathname in - * a malloc'ed buffer. + * This routine is responsible for finding dependencies of userland + * initiated kldload(2)'s of files. */ -char *linker_search_path(const char *filename); +int linker_load_dependancies(linker_file_t lf); /* * DDB Helpers, tuned specifically for ddb/db_kld.c diff --git a/sys/sys/module.h b/sys/sys/module.h index 800f45a..e5f0547 100644 --- a/sys/sys/module.h +++ b/sys/sys/module.h @@ -29,6 +29,17 @@ #ifndef _SYS_MODULE_H_ #define _SYS_MODULE_H_ +/* + * Module metadata types + */ +#define MDT_DEPEND 1 /* argument is a module name */ +#define MDT_MODULE 2 /* module declaration */ +#define MDT_VERSION 3 /* module version(s) */ + +#define MDT_STRUCT_VERSION 1 /* version of metadata structure */ + +#define MDT_SETNAME "modmetadata_set" + typedef enum modeventtype { MOD_LOAD, MOD_UNLOAD, @@ -60,12 +71,63 @@ typedef union modspecific { u_long ulongval; } modspecific_t; +/* + * Module dependency declarartion + */ +struct mod_depend { + int md_ver_minimum; + int md_ver_preferred; + int md_ver_maximum; +}; + +/* + * Module version declaration + */ +struct mod_version { + int mv_version; +}; + +struct mod_metadata { + int md_version; /* structure version MDTV_* */ + int md_type; /* type of entry MDT_* */ + void *md_data; /* specific data */ + char *md_cval; /* common string label */ +}; + #ifdef _KERNEL +#include <sys/linker_set.h> + +#define MODULE_METADATA(uniquifier, type, data, cval) \ + static struct mod_metadata _mod_metadata ## uniquifier = { \ + MDT_STRUCT_VERSION, \ + type, \ + data, \ + cval \ + }; \ + DATA_SET(modmetadata_set, _mod_metadata ## uniquifier) + +#define MODULE_DEPEND(module, mdepend, vmin, vpref, vmax) \ + static struct mod_depend _ ##module ## _depend_on_ ## mdepend = { \ + vmin, \ + vpref, \ + vmax \ + }; \ + MODULE_METADATA(_md_ ##module ## _on_ ##mdepend, MDT_DEPEND, \ + &_ ##module ## _depend_on_ ##mdepend, #mdepend) + #define DECLARE_MODULE(name, data, sub, order) \ + MODULE_METADATA(_md_ ##name, MDT_MODULE, &data, #name); \ SYSINIT(name##module, sub, order, module_register_init, &data) \ struct __hack +#define MODULE_VERSION(module, version) \ + static struct mod_version _ ## module ## _version = { \ + version \ + }; \ + MODULE_METADATA(_ ## module ## _version, MDT_VERSION, \ + & _ ## module ## _version, #module) + void module_register_init(const void *data); struct linker_file; int module_register(const struct moduledata *data, struct linker_file *lf); |