X-Git-Url: https://gitweb.dragonflybsd.org/dragonfly.git/blobdiff_plain/af68c4e166819cbb4ad4c22ddc23c34b8f47ec99..6ef6faeb19268917889c5a06b0fa523ae6d67ccd:/sys/kern/kern_linker.c diff --git a/sys/kern/kern_linker.c b/sys/kern/kern_linker.c index 2eb65324cd..c1159f346b 100644 --- a/sys/kern/kern_linker.c +++ b/sys/kern/kern_linker.c @@ -24,7 +24,7 @@ * SUCH DAMAGE. * * $FreeBSD: src/sys/kern/kern_linker.c,v 1.41.2.3 2001/11/21 17:50:35 luigi Exp $ - * $DragonFly: src/sys/kern/kern_linker.c,v 1.21 2005/03/29 00:35:55 drhodus Exp $ + * $DragonFly: src/sys/kern/kern_linker.c,v 1.38 2007/06/07 22:58:11 corecode Exp $ */ #include "opt_ddb.h" @@ -47,6 +47,10 @@ #include +#ifdef _KERNEL_VIRTUAL +#include +#endif + #ifdef KLD_DEBUG int kld_debug = 0; #endif @@ -66,12 +70,12 @@ static int next_file_id = 1; static void linker_init(void* arg) { - lockinit(&lock, 0, "klink", 0, 0); + lockinit(&lock, "klink", 0, 0); TAILQ_INIT(&classes); TAILQ_INIT(&linker_files); } -SYSINIT(linker, SI_SUB_KLD, SI_ORDER_FIRST, linker_init, 0); +SYSINIT(linker, SI_BOOT2_KLD, SI_ORDER_FIRST, linker_init, 0); int linker_add_class(const char* desc, void* priv, @@ -79,7 +83,7 @@ linker_add_class(const char* desc, void* priv, { linker_class_t lc; - lc = malloc(sizeof(struct linker_class), M_LINKER, M_NOWAIT); + lc = kmalloc(sizeof(struct linker_class), M_LINKER, M_NOWAIT); if (!lc) return ENOMEM; bzero(lc, sizeof(*lc)); @@ -114,7 +118,7 @@ linker_file_sysinit(linker_file_t lf) moddata = (*sipp)->udata; error = module_register(moddata, lf); if (error) { - printf("linker_file_sysinit \"%s\" failed to register! %d\n", + kprintf("linker_file_sysinit \"%s\" failed to register! %d\n", lf->filename, error); return error; } @@ -146,7 +150,7 @@ linker_file_sysinit(linker_file_t lf) * Perform each task, and continue on to the next task. */ for (sipp = start; sipp < stop; sipp++) { - if ((*sipp)->subsystem == SI_SUB_DUMMY) + if ((*sipp)->subsystem == SI_SPECIAL_DUMMY) continue; /* skip dummy task(s)*/ /* Call function */ @@ -194,7 +198,7 @@ linker_file_sysuninit(linker_file_t lf) * Perform each task, and continue on to the next task. */ for (sipp = start; sipp < stop; sipp++) { - if ((*sipp)->subsystem == SI_SUB_DUMMY) + if ((*sipp)->subsystem == SI_SPECIAL_DUMMY) continue; /* skip dummy task(s)*/ /* Call function */ @@ -239,7 +243,7 @@ linker_load_file(const char* filename, linker_file_t* result) char *koname = NULL; /* Refuse to load modules if securelevel raised */ - if (securelevel > 0) + if (securelevel > 0 || kernel_mem_readonly) return EPERM; lf = linker_find_file_by_name(filename); @@ -256,12 +260,12 @@ linker_load_file(const char* filename, linker_file_t* result) goto out; } - koname = malloc(strlen(filename) + 4, M_LINKER, M_WAITOK); + koname = kmalloc(strlen(filename) + 4, M_LINKER, M_WAITOK); if (koname == NULL) { error = ENOMEM; goto out; } - sprintf(koname, "%s.ko", filename); + ksprintf(koname, "%s.ko", filename); lf = NULL; foundfile = 0; for (lc = TAILQ_FIRST(&classes); lc; lc = TAILQ_NEXT(lc, link)) { @@ -306,7 +310,7 @@ linker_load_file(const char* filename, linker_file_t* result) out: if (koname) - free(koname, M_LINKER); + kfree(koname, M_LINKER); return error; } @@ -321,23 +325,23 @@ linker_find_file_by_name(const char* filename) ; filename += i; - koname = malloc(strlen(filename) + 4, M_LINKER, M_WAITOK); + koname = kmalloc(strlen(filename) + 4, M_LINKER, M_WAITOK); if (koname == NULL) goto out; - sprintf(koname, "%s.ko", filename); + ksprintf(koname, "%s.ko", filename); - lockmgr(&lock, LK_SHARED, NULL, curthread); + lockmgr(&lock, LK_SHARED); for (lf = TAILQ_FIRST(&linker_files); lf; lf = TAILQ_NEXT(lf, link)) { if (!strcmp(lf->filename, koname)) break; if (!strcmp(lf->filename, filename)) break; } - lockmgr(&lock, LK_RELEASE, NULL, curthread); + lockmgr(&lock, LK_RELEASE); out: if (koname) - free(koname, M_LINKER); + kfree(koname, M_LINKER); return lf; } @@ -346,11 +350,11 @@ linker_find_file_by_id(int fileid) { linker_file_t lf = 0; - lockmgr(&lock, LK_SHARED, NULL, curthread); + lockmgr(&lock, LK_SHARED); for (lf = TAILQ_FIRST(&linker_files); lf; lf = TAILQ_NEXT(lf, link)) if (lf->id == fileid) break; - lockmgr(&lock, LK_RELEASE, NULL, curthread); + lockmgr(&lock, LK_RELEASE); return lf; } @@ -369,9 +373,9 @@ linker_make_file(const char* pathname, void* priv, struct linker_file_ops* ops) filename = pathname; KLD_DPF(FILE, ("linker_make_file: new file, filename=%s\n", filename)); - lockmgr(&lock, LK_EXCLUSIVE, NULL, curthread); + lockmgr(&lock, LK_EXCLUSIVE); namelen = strlen(filename) + 1; - lf = malloc(sizeof(struct linker_file) + namelen, M_LINKER, M_WAITOK); + lf = kmalloc(sizeof(struct linker_file) + namelen, M_LINKER, M_WAITOK); if (!lf) goto out; bzero(lf, sizeof(*lf)); @@ -392,7 +396,7 @@ linker_make_file(const char* pathname, void* priv, struct linker_file_ops* ops) TAILQ_INSERT_TAIL(&linker_files, lf, link); out: - lockmgr(&lock, LK_RELEASE, NULL, curthread); + lockmgr(&lock, LK_RELEASE); return lf; } @@ -405,11 +409,11 @@ linker_file_unload(linker_file_t file) int i; /* Refuse to unload modules if securelevel raised */ - if (securelevel > 0) + if (securelevel > 0 || kernel_mem_readonly) return EPERM; KLD_DPF(FILE, ("linker_file_unload: lf->refs=%d\n", file->refs)); - lockmgr(&lock, LK_EXCLUSIVE, NULL, curthread); + lockmgr(&lock, LK_EXCLUSIVE); if (file->refs == 1) { KLD_DPF(FILE, ("linker_file_unload: file is unloading, informing modules\n")); /* @@ -430,7 +434,8 @@ linker_file_unload(linker_file_t file) if ((error = module_unload(mod)) != 0) { KLD_DPF(FILE, ("linker_file_unload: module %x vetoes unload\n", mod)); - lockmgr(&lock, LK_RELEASE, NULL, curthread); + lockmgr(&lock, LK_RELEASE); + file->refs--; goto out; } @@ -452,14 +457,14 @@ linker_file_unload(linker_file_t file) mod; mod = module_getfnext(mod) ) { - printf("linker_file_unload: module %p still has refs!\n", mod); + kprintf("linker_file_unload: module %p still has refs!\n", mod); } --file->refs; } file->refs--; if (file->refs > 0) { - lockmgr(&lock, LK_RELEASE, NULL, curthread); + lockmgr(&lock, LK_RELEASE); goto out; } @@ -470,20 +475,20 @@ linker_file_unload(linker_file_t file) } TAILQ_REMOVE(&linker_files, file, link); - lockmgr(&lock, LK_RELEASE, NULL, curthread); + lockmgr(&lock, LK_RELEASE); for (i = 0; i < file->ndeps; i++) linker_file_unload(file->deps[i]); - free(file->deps, M_LINKER); + kfree(file->deps, M_LINKER); for (cp = STAILQ_FIRST(&file->common); cp; cp = STAILQ_FIRST(&file->common)) { STAILQ_REMOVE(&file->common, cp, common_symbol, link); - free(cp, M_LINKER); + kfree(cp, M_LINKER); } file->ops->unload(file); - free(file, M_LINKER); + kfree(file, M_LINKER); out: return error; @@ -494,7 +499,7 @@ linker_file_add_dependancy(linker_file_t file, linker_file_t dep) { linker_file_t* newdeps; - newdeps = malloc((file->ndeps + 1) * sizeof(linker_file_t*), + newdeps = kmalloc((file->ndeps + 1) * sizeof(linker_file_t*), M_LINKER, M_WAITOK); if (newdeps == NULL) return ENOMEM; @@ -502,7 +507,7 @@ linker_file_add_dependancy(linker_file_t file, linker_file_t dep) if (file->deps) { bcopy(file->deps, newdeps, file->ndeps * sizeof(linker_file_t*)); - free(file->deps, M_LINKER); + kfree(file->deps, M_LINKER); } file->deps = newdeps; file->deps[file->ndeps] = dep; @@ -600,7 +605,7 @@ linker_file_lookup_symbol(linker_file_t file, const char* name, int deps, caddr_ * Round the symbol size up to align. */ common_size = (common_size + sizeof(int) - 1) & -sizeof(int); - cp = malloc(sizeof(struct common_symbol) + cp = kmalloc(sizeof(struct common_symbol) + common_size + strlen(name) + 1, M_LINKER, M_WAITOK); @@ -621,6 +626,14 @@ linker_file_lookup_symbol(linker_file_t file, const char* name, int deps, caddr_ return 0; } +#ifdef _KERNEL_VIRTUAL + *raddr = dlsym(RTLD_NEXT, name); + if (*raddr != NULL) { + KLD_DPF(SYM, ("linker_file_lookup_symbol: found dlsym=%x\n", *raddr)); + return 0; + } +#endif + KLD_DPF(SYM, ("linker_file_lookup_symbol: fail\n")); return ENOENT; } @@ -698,7 +711,7 @@ linker_ddb_symbol_values(c_linker_sym_t sym, linker_symval_t *symval) */ int -kldload(struct kldload_args *uap) +sys_kldload(struct kldload_args *uap) { struct thread *td = curthread; char* filename = NULL, *modulename; @@ -707,13 +720,13 @@ kldload(struct kldload_args *uap) uap->sysmsg_result = -1; - if (securelevel > 0) /* redundant, but that's OK */ + if (securelevel > 0 || kernel_mem_readonly) /* redundant, but that's OK */ return EPERM; if ((error = suser(td)) != 0) return error; - filename = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); + filename = kmalloc(MAXPATHLEN, M_TEMP, M_WAITOK); if ((error = copyinstr(uap->file, filename, MAXPATHLEN, NULL)) != 0) goto out; @@ -736,18 +749,18 @@ kldload(struct kldload_args *uap) out: if (filename) - free(filename, M_TEMP); + kfree(filename, M_TEMP); return error; } int -kldunload(struct kldunload_args *uap) +sys_kldunload(struct kldunload_args *uap) { struct thread *td = curthread; linker_file_t lf; int error = 0; - if (securelevel > 0) /* redundant, but that's OK */ + if (securelevel > 0 || kernel_mem_readonly) /* redundant, but that's OK */ return EPERM; if ((error = suser(td)) != 0) @@ -757,7 +770,7 @@ kldunload(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"); + kprintf("linkerunload: attempt to unload file that was loaded by the kernel\n"); error = EBUSY; goto out; } @@ -773,7 +786,7 @@ out: } int -kldfind(struct kldfind_args *uap) +sys_kldfind(struct kldfind_args *uap) { char *filename = NULL, *modulename; linker_file_t lf; @@ -781,7 +794,7 @@ kldfind(struct kldfind_args *uap) uap->sysmsg_result = -1; - filename = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); + filename = kmalloc(MAXPATHLEN, M_TEMP, M_WAITOK); if ((error = copyinstr(uap->file, filename, MAXPATHLEN, NULL)) != 0) goto out; @@ -797,12 +810,12 @@ kldfind(struct kldfind_args *uap) out: if (filename) - free(filename, M_TEMP); + kfree(filename, M_TEMP); return error; } int -kldnext(struct kldnext_args *uap) +sys_kldnext(struct kldnext_args *uap) { linker_file_t lf; int error = 0; @@ -828,7 +841,7 @@ kldnext(struct kldnext_args *uap) } int -kldstat(struct kldstat_args *uap) +sys_kldstat(struct kldstat_args *uap) { linker_file_t lf; int error = 0; @@ -875,7 +888,7 @@ out: } int -kldfirstmod(struct kldfirstmod_args *uap) +sys_kldfirstmod(struct kldfirstmod_args *uap) { linker_file_t lf; int error = 0; @@ -893,7 +906,7 @@ kldfirstmod(struct kldfirstmod_args *uap) } int -kldsym(struct kldsym_args *uap) +sys_kldsym(struct kldsym_args *uap) { char *symstr = NULL; c_linker_sym_t sym; @@ -909,7 +922,7 @@ kldsym(struct kldsym_args *uap) goto out; } - symstr = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); + symstr = kmalloc(MAXPATHLEN, M_TEMP, M_WAITOK); if ((error = copyinstr(lookup.symname, symstr, MAXPATHLEN, NULL)) != 0) goto out; @@ -941,7 +954,7 @@ kldsym(struct kldsym_args *uap) } out: if (symstr) - free(symstr, M_TEMP); + kfree(symstr, M_TEMP); return error; } @@ -975,8 +988,7 @@ find_mod_metadata(const char *modname) if (mdt->md_type != MDT_MODULE) continue; if (strlen(mdt->md_cval) == len && - strncmp(mdt->md_cval, modname, len) == 0 - ) { + strncmp(mdt->md_cval, modname, len) == 0) { return(mdt); } } @@ -1004,11 +1016,11 @@ linker_preload(void* arg) modname = (char *)preload_search_info(modptr, MODINFO_NAME); modtype = (char *)preload_search_info(modptr, MODINFO_TYPE); if (modname == NULL) { - printf("Preloaded module at %p does not have a name!\n", modptr); + kprintf("Preloaded module at %p does not have a name!\n", modptr); continue; } if (modtype == NULL) { - printf("Preloaded module at %p does not have a type!\n", modptr); + kprintf("Preloaded module at %p does not have a type!\n", modptr); continue; } @@ -1016,15 +1028,16 @@ linker_preload(void* arg) * This is a hack at the moment, but what's in FreeBSD-5 is even * worse so I'd rather the hack. */ - printf("Preloaded %s \"%s\" at %p", modtype, modname, modptr); + kprintf("Preloaded %s \"%s\" at %p", modtype, modname, modptr); if (find_mod_metadata(modname)) { - printf(" (ignored, already in static kernel)\n"); + kprintf(" (ignored, already in static kernel)\n"); continue; } - printf(".\n"); + kprintf(".\n"); lf = linker_find_file_by_name(modname); if (lf) { + lf->refs++; lf->userrefs++; continue; } @@ -1050,7 +1063,7 @@ linker_preload(void* arg) moddata = (*sipp)->udata; error = module_register(moddata, lf); if (error) - printf("Preloaded %s \"%s\" failed to register: %d\n", + kprintf("Preloaded %s \"%s\" failed to register: %d\n", modtype, modname, error); } } @@ -1061,7 +1074,7 @@ linker_preload(void* arg) } } -SYSINIT(preload, SI_SUB_KLD, SI_ORDER_MIDDLE, linker_preload, 0); +SYSINIT(preload, SI_BOOT2_KLD, SI_ORDER_MIDDLE, linker_preload, 0); /* * Search for a not-loaded module by name. @@ -1078,17 +1091,18 @@ SYSINIT(preload, SI_SUB_KLD, SI_ORDER_MIDDLE, linker_preload, 0); * character as a separator to be consistent with the bootloader. */ -static char linker_path[MAXPATHLEN] = "/;/boot/;/modules/"; +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"); +TUNABLE_STR("module_path", linker_path, sizeof(linker_path)); static char * linker_strdup(const char *str) { char *result; - if ((result = malloc((strlen(str) + 1), M_LINKER, M_WAITOK)) != NULL) + if ((result = kmalloc((strlen(str) + 1), M_LINKER, M_WAITOK)) != NULL) strcpy(result, str); return(result); } @@ -1098,6 +1112,8 @@ linker_search_path(const char *name) { struct nlookupdata nd; char *cp, *ep, *result; + size_t name_len, prefix_len; + int sep; int error; enum vtype type; @@ -1107,17 +1123,28 @@ linker_search_path(const char *name) /* traverse the linker path */ cp = linker_path; + name_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); - if (result == NULL) /* actually ENOMEM */ - return(NULL); + prefix_len = ep - cp; + /* if this component doesn't end with a slash, add one */ + if (ep == cp || *(ep - 1) != '/') + sep = 1; + else + sep = 0; + + /* + * +2 : possible separator, plus terminator. + */ + result = kmalloc(prefix_len + name_len + 2, M_LINKER, M_WAITOK); - strncpy(result, cp, ep - cp); - strcpy(result + (ep - cp), name); + strncpy(result, cp, prefix_len); + if (sep) + result[prefix_len++] = '/'; + strcpy(result + prefix_len, name); /* * Attempt to open the file, and return the path if we succeed and it's @@ -1134,7 +1161,7 @@ linker_search_path(const char *name) } } nlookup_done(&nd); - free(result, M_LINKER); + kfree(result, M_LINKER); if (*ep == 0) break;