diff options
Diffstat (limited to 'freebsd/sys/kern/kern_linker.c')
-rw-r--r-- | freebsd/sys/kern/kern_linker.c | 118 |
1 files changed, 65 insertions, 53 deletions
diff --git a/freebsd/sys/kern/kern_linker.c b/freebsd/sys/kern/kern_linker.c index 39664a85..a115aa96 100644 --- a/freebsd/sys/kern/kern_linker.c +++ b/freebsd/sys/kern/kern_linker.c @@ -30,6 +30,7 @@ __FBSDID("$FreeBSD$"); #include <rtems/bsd/local/opt_ddb.h> +#include <rtems/bsd/local/opt_kld.h> #include <rtems/bsd/local/opt_hwpmc_hooks.h> #include <rtems/bsd/sys/param.h> @@ -55,6 +56,10 @@ __FBSDID("$FreeBSD$"); #include <sys/syscallsubr.h> #include <sys/sysctl.h> +#ifdef DDB +#include <ddb/ddb.h> +#endif + #include <net/vnet.h> #include <security/mac/mac_framework.h> @@ -68,10 +73,16 @@ __FBSDID("$FreeBSD$"); #ifndef __rtems__ #ifdef KLD_DEBUG int kld_debug = 0; -SYSCTL_INT(_debug, OID_AUTO, kld_debug, CTLFLAG_RW, - &kld_debug, 0, "Set various levels of KLD debug"); +SYSCTL_INT(_debug, OID_AUTO, kld_debug, CTLFLAG_RWTUN, + &kld_debug, 0, "Set various levels of KLD debug"); #endif +/* These variables are used by kernel debuggers to enumerate loaded files. */ +const int kld_off_address = offsetof(struct linker_file, address); +const int kld_off_filename = offsetof(struct linker_file, filename); +const int kld_off_pathname = offsetof(struct linker_file, pathname); +const int kld_off_next = offsetof(struct linker_file, link.tqe_next); + /* * static char *linker_search_path(const char *name, struct mod_depend * *verinfo); @@ -143,18 +154,8 @@ static caddr_t linker_file_lookup_symbol_internal(linker_file_t file, const char* name, int deps); static int linker_load_module(const char *kldname, const char *modname, struct linker_file *parent, - struct mod_depend *verinfo, struct linker_file **lfpp); -static modlist_t modlist_lookup2(const char *name, struct mod_depend *verinfo); - -static char * -linker_strdup(const char *str) -{ - char *result; - - if ((result = malloc((strlen(str) + 1), M_LINKER, M_WAITOK)) != NULL) - strcpy(result, str); - return (result); -} + const struct mod_depend *verinfo, struct linker_file **lfpp); +static modlist_t modlist_lookup2(const char *name, const struct mod_depend *verinfo); static void linker_init(void *arg) @@ -306,10 +307,10 @@ linker_file_register_sysctls(linker_file_t lf) return; sx_xunlock(&kld_sx); - sysctl_lock(); + sysctl_wlock(); for (oidp = start; oidp < stop; oidp++) sysctl_register_oid(*oidp); - sysctl_unlock(); + sysctl_wunlock(); sx_xlock(&kld_sx); } @@ -318,7 +319,7 @@ linker_file_unregister_sysctls(linker_file_t lf) { struct sysctl_oid **start, **stop, **oidp; - KLD_DPF(FILE, ("linker_file_unregister_sysctls: registering SYSCTLs" + KLD_DPF(FILE, ("linker_file_unregister_sysctls: unregistering SYSCTLs" " for %s\n", lf->filename)); sx_assert(&kld_sx, SA_XLOCKED); @@ -327,10 +328,10 @@ linker_file_unregister_sysctls(linker_file_t lf) return; sx_xunlock(&kld_sx); - sysctl_lock(); + sysctl_wlock(); for (oidp = start; oidp < stop; oidp++) sysctl_unregister_oid(*oidp); - sysctl_unlock(); + sysctl_wunlock(); sx_xlock(&kld_sx); } #endif /* __rtems__ */ @@ -598,11 +599,13 @@ linker_make_file(const char *pathname, linker_class_t lc) lf = (linker_file_t)kobj_create((kobj_class_t)lc, M_LINKER, M_WAITOK); if (lf == NULL) return (NULL); + lf->ctors_addr = 0; + lf->ctors_size = 0; lf->refs = 1; lf->userrefs = 0; lf->flags = 0; - lf->filename = linker_strdup(filename); - lf->pathname = linker_strdup(pathname); + lf->filename = strdup(filename, M_LINKER); + lf->pathname = strdup(pathname, M_LINKER); LINKER_GET_NEXT_FILE_ID(lf->id); lf->ndeps = 0; lf->deps = NULL; @@ -966,7 +969,7 @@ linker_debug_search_symbol_name(caddr_t value, char *buf, u_int buflen, * * Note that we do not obey list locking protocols here. We really don't need * DDB to hang because somebody's got the lock held. We'll take the chance - * that the files list is inconsistant instead. + * that the files list is inconsistent instead. */ #ifdef DDB int @@ -1009,9 +1012,9 @@ linker_search_symbol_name(caddr_t value, char *buf, u_int buflen, { int error; - sx_xlock(&kld_sx); + sx_slock(&kld_sx); error = linker_debug_search_symbol_name(value, buf, buflen, offset); - sx_xunlock(&kld_sx); + sx_sunlock(&kld_sx); return (error); } @@ -1042,7 +1045,7 @@ kern_kldload(struct thread *td, const char *file, int *fileid) * (kldname.ko, or kldname.ver.ko) treat it as an interface * name. */ - if (index(file, '/') || index(file, '.')) { + if (strchr(file, '/') || strchr(file, '.')) { kldname = file; modname = NULL; } else { @@ -1273,6 +1276,23 @@ kern_kldstat(struct thread *td, int fileid, struct kld_file_stat *stat) return (0); } +#ifdef DDB +DB_COMMAND(kldstat, db_kldstat) +{ + linker_file_t lf; + +#define POINTER_WIDTH ((int)(sizeof(void *) * 2 + 2)) + db_printf("Id Refs Address%*c Size Name\n", POINTER_WIDTH - 7, ' '); +#undef POINTER_WIDTH + TAILQ_FOREACH(lf, &linker_files, link) { + if (db_pager_quit) + return; + db_printf("%2d %4d %p %-8zx %s\n", lf->id, lf->refs, + lf->address, lf->size, lf->filename); + } +} +#endif /* DDB */ + int sys_kldfirstmod(struct thread *td, struct kldfirstmod_args *uap) { @@ -1376,7 +1396,7 @@ modlist_lookup(const char *name, int ver) } static modlist_t -modlist_lookup2(const char *name, struct mod_depend *verinfo) +modlist_lookup2(const char *name, const struct mod_depend *verinfo) { modlist_t mod, bestmod; int ver; @@ -1426,7 +1446,7 @@ linker_addmodules(linker_file_t lf, struct mod_metadata **start, if (mp->md_type != MDT_VERSION) continue; modname = mp->md_cval; - ver = ((struct mod_version *)mp->md_data)->mv_version; + ver = ((const struct mod_version *)mp->md_data)->mv_version; if (modlist_lookup(modname, ver) != NULL) { printf("module %s already present!\n", modname); /* XXX what can we do? this is a build error. :-( */ @@ -1449,7 +1469,7 @@ linker_preload(void *arg) linker_file_list_t depended_files; struct mod_metadata *mp, *nmp; struct mod_metadata **start, **stop, **mdp, **nmdp; - struct mod_depend *verinfo; + const struct mod_depend *verinfo; int nver; int resolves; modlist_t mod; @@ -1547,7 +1567,7 @@ restart: if (mp->md_type != MDT_VERSION) continue; modname = mp->md_cval; - nver = ((struct mod_version *) + nver = ((const struct mod_version *) mp->md_data)->mv_version; if (modlist_lookup(modname, nver) != NULL) { @@ -1667,7 +1687,7 @@ SYSINIT(preload, SI_SUB_KLD, SI_ORDER_MIDDLE, linker_preload, 0); static char linker_hintfile[] = "linker.hints"; static char linker_path[MAXPATHLEN] = "/boot/kernel;/boot/modules"; -SYSCTL_STRING(_kern, OID_AUTO, module_path, CTLFLAG_RW, linker_path, +SYSCTL_STRING(_kern, OID_AUTO, module_path, CTLFLAG_RWTUN, linker_path, sizeof(linker_path), "module load search path"); TUNABLE_STR("module_path", linker_path, sizeof(linker_path)); @@ -1690,7 +1710,7 @@ linker_lookup_file(const char *path, int pathlen, const char *name, struct nameidata nd; struct thread *td = curthread; /* XXX */ char *result, **cpp, *sep; - int error, len, extlen, reclen, flags, vfslocked; + int error, len, extlen, reclen, flags; enum vtype type; extlen = 0; @@ -1711,18 +1731,16 @@ linker_lookup_file(const char *path, int pathlen, const char *name, * Attempt to open the file, and return the path if * we succeed and it's a regular file. */ - NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, result, td); + NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, result, td); flags = FREAD; error = vn_open(&nd, &flags, 0, NULL); if (error == 0) { - vfslocked = NDHASGIANT(&nd); NDFREE(&nd, NDF_ONLY_PNBUF); type = nd.ni_vp->v_type; if (vap) VOP_GETATTR(nd.ni_vp, vap, td->td_ucred); VOP_UNLOCK(nd.ni_vp, 0); vn_close(nd.ni_vp, FREAD, td->td_ucred, td); - VFS_UNLOCK_GIANT(vfslocked); if (type == VREG) return (result); } @@ -1732,7 +1750,7 @@ linker_lookup_file(const char *path, int pathlen, const char *name, } #define INT_ALIGN(base, ptr) ptr = \ - (base) + (((ptr) - (base) + sizeof(int) - 1) & ~(sizeof(int) - 1)) + (base) + roundup2((ptr) - (base), sizeof(int)) /* * Lookup KLD which contains requested module in the "linker.hints" file. If @@ -1741,7 +1759,7 @@ linker_lookup_file(const char *path, int pathlen, const char *name, */ static char * linker_hints_lookup(const char *path, int pathlen, const char *modname, - int modnamelen, struct mod_depend *verinfo) + int modnamelen, const struct mod_depend *verinfo) { struct thread *td = curthread; /* XXX */ struct ucred *cred = td ? td->td_ucred : NULL; @@ -1751,7 +1769,6 @@ linker_hints_lookup(const char *path, int pathlen, const char *modname, u_char *cp, *recptr, *bufend, *result, *best, *pathbuf, *sep; int error, ival, bestver, *intp, found, flags, clen, blen; ssize_t reclen; - int vfslocked = 0; result = NULL; bestver = found = 0; @@ -1763,12 +1780,11 @@ linker_hints_lookup(const char *path, int pathlen, const char *modname, snprintf(pathbuf, reclen, "%.*s%s%s", pathlen, path, sep, linker_hintfile); - NDINIT(&nd, LOOKUP, NOFOLLOW | MPSAFE, UIO_SYSSPACE, pathbuf, td); + NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_SYSSPACE, pathbuf, td); flags = FREAD; error = vn_open(&nd, &flags, 0, NULL); if (error) goto bad; - vfslocked = NDHASGIANT(&nd); NDFREE(&nd, NDF_ONLY_PNBUF); if (nd.ni_vp->v_type != VREG) goto bad; @@ -1779,20 +1795,17 @@ linker_hints_lookup(const char *path, int pathlen, const char *modname, /* * XXX: we need to limit this number to some reasonable value */ - if (vattr.va_size > 100 * 1024) { + if (vattr.va_size > LINKER_HINTS_MAX) { printf("hints file too large %ld\n", (long)vattr.va_size); goto bad; } hints = malloc(vattr.va_size, M_TEMP, M_WAITOK); - if (hints == NULL) - goto bad; error = vn_rdwr(UIO_READ, nd.ni_vp, (caddr_t)hints, vattr.va_size, 0, UIO_SYSSPACE, IO_NODELOCKED, cred, NOCRED, &reclen, td); if (error) goto bad; VOP_UNLOCK(nd.ni_vp, 0); vn_close(nd.ni_vp, FREAD, cred, td); - VFS_UNLOCK_GIANT(vfslocked); nd.ni_vp = NULL; if (reclen != 0) { printf("can't read %zd\n", reclen); @@ -1861,7 +1874,6 @@ bad: if (nd.ni_vp != NULL) { VOP_UNLOCK(nd.ni_vp, 0); vn_close(nd.ni_vp, FREAD, cred, td); - VFS_UNLOCK_GIANT(vfslocked); } /* * If nothing found or hints is absent - fallback to the old @@ -1878,7 +1890,7 @@ bad: */ static char * linker_search_module(const char *modname, int modnamelen, - struct mod_depend *verinfo) + const struct mod_depend *verinfo) { char *cp, *ep, *result; @@ -1908,8 +1920,8 @@ linker_search_kld(const char *name) int len; /* qualified at all? */ - if (index(name, '/')) - return (linker_strdup(name)); + if (strchr(name, '/')) + return (strdup(name, M_LINKER)); /* traverse the linker path */ len = strlen(name); @@ -1929,7 +1941,7 @@ linker_basename(const char *path) { const char *filename; - filename = rindex(path, '/'); + filename = strrchr(path, '/'); if (filename == NULL) return path; if (filename[1]) @@ -1982,7 +1994,7 @@ linker_hwpmc_list_objects(void) */ static int linker_load_module(const char *kldname, const char *modname, - struct linker_file *parent, struct mod_depend *verinfo, + struct linker_file *parent, const struct mod_depend *verinfo, struct linker_file **lfpp) { linker_file_t lfdep; @@ -2002,7 +2014,7 @@ linker_load_module(const char *kldname, const char *modname, if (modlist_lookup2(modname, verinfo) != NULL) return (EEXIST); if (kldname != NULL) - pathname = linker_strdup(kldname); + pathname = strdup(kldname, M_LINKER); else if (rootvnode == NULL) pathname = NULL; else @@ -2056,13 +2068,13 @@ linker_load_dependencies(linker_file_t lf) linker_file_t lfdep; struct mod_metadata **start, **stop, **mdp, **nmdp; struct mod_metadata *mp, *nmp; - struct mod_depend *verinfo; + const struct mod_depend *verinfo; modlist_t mod; const char *modname, *nmodname; int ver, error = 0, count; /* - * All files are dependant on /kernel. + * All files are dependent on /kernel. */ sx_assert(&kld_sx, SA_XLOCKED); if (linker_kernel_file) { @@ -2079,7 +2091,7 @@ linker_load_dependencies(linker_file_t lf) if (mp->md_type != MDT_VERSION) continue; modname = mp->md_cval; - ver = ((struct mod_version *)mp->md_data)->mv_version; + ver = ((const struct mod_version *)mp->md_data)->mv_version; mod = modlist_lookup(modname, ver); if (mod != NULL) { printf("interface %s.%d already present in the KLD" |