summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/kern/kern_linker.c
diff options
context:
space:
mode:
Diffstat (limited to 'freebsd/sys/kern/kern_linker.c')
-rw-r--r--freebsd/sys/kern/kern_linker.c118
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"