First round implementation of a fine grain enhanced module to module

version dependency system.  This isn't quite finished, but it is at a
useful stage to do a functional checkpoint.

Highlights:
- version and dependency metadata is gathered via linker sets, so things
are handled the same for static kernels and code built to live in a kld.
- The dependencies are at module level (versus at file level).
- Dependencies determine kld symbol search order - this means that you
cannot link against symbols in another file unless you depend on it. This
is so that you cannot accidently unload the target out from underneath
the ones referencing it.
- It is flexible enough that we can put tags in #include files and macros
so that we can get decent hooks for enforcing recompiles on incompatable
ABI changes.  eg: if we change struct proc, we could force a recompile
for all kld's that reference the proc struct.
- Tangled dependency references at boot time are sorted.  Files are
relocated once all their dependencies are already relocated.

Caveats:
- Loader support is incomplete, but has been worked on seperately.
- Actual enforcement of the version number tags is not active yet - just
the module dependencies are live.  The actual structure of versioning
hasn't been agreed on yet. (eg: major.minor, or whatever)
- There is some backwards compatability for old modules without metadata
but I'm not sure how good it is.

This is based on work originally done by Boris Popov (bp@freebsd.org),
but I'm not sure he'd recognize much of it now. Don't blame him. :-)
Also, ideas have been borrowed from Mike Smith.
This commit is contained in:
Peter Wemm 2000-04-29 13:19:31 +00:00
parent 18616dacbb
commit 54823af256
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=59751
8 changed files with 732 additions and 412 deletions

View File

@ -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 @@ kldunload(struct proc* p, struct kldunload_args* uap)
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 @@ kldsym(struct proc *p, struct kldsym_args *uap)
* 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);
}
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);
}
}
sysinit_add((struct sysinit **)sysinits->ls_items);
/*
* 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;
}
linker_file_register_sysctls(lf);
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);
}
}
/*
* 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);
}
}
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;
}

View File

@ -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;

View File

@ -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;
/* Try to load dependancies */
if (((error = load_dependancies(af)) != 0) ||
((error = relocate_file(af)) != 0)) {
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_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);
}
return(0);
}
static int
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)
{

View File

@ -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;
}
error = relocate_file(ef);
if (error) {
linker_file_unload(lf);
return error;
}
(void)parse_module_symbols(ef);
lf->flags |= LINKER_FILE_LINKED;
#ifdef DDB
GDB_STATE(RT_ADD);
ef->gdb.l_addr = lf->address;
ef->gdb.l_name = 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_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)
return error;
(void)link_elf_preload_parse_symbols(ef);
#ifdef DDB
GDB_STATE(RT_ADD);
ef->gdb.l_addr = lf->address;
ef->gdb.l_name = lf->filename;
ef->gdb.l_ld = ef->dynamic;
link_elf_add_gdb(&ef->gdb);
GDB_STATE(RT_CONSISTENT);
#endif
return (0);
}
static int
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)
{

View File

@ -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;
}
error = relocate_file(ef);
if (error) {
linker_file_unload(lf);
return error;
}
(void)parse_module_symbols(ef);
lf->flags |= LINKER_FILE_LINKED;
#ifdef DDB
GDB_STATE(RT_ADD);
ef->gdb.l_addr = lf->address;
ef->gdb.l_name = 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_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)
return error;
(void)link_elf_preload_parse_symbols(ef);
#ifdef DDB
GDB_STATE(RT_ADD);
ef->gdb.l_addr = lf->address;
ef->gdb.l_name = lf->filename;
ef->gdb.l_ld = ef->dynamic;
link_elf_add_gdb(&ef->gdb);
GDB_STATE(RT_CONSISTENT);
#endif
return (0);
}
static int
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)
{

View File

@ -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;
};

View File

@ -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 */
};
/*
@ -90,12 +91,6 @@ struct linker_class {
TAILQ_ENTRY(linker_class) link; /* list of all file classes */
};
/*
* 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.
*/
@ -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

View File

@ -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);