summaryrefslogtreecommitdiffstats
path: root/sys/kern/kern_linker.c
diff options
context:
space:
mode:
authorbp <bp@FreeBSD.org>2001-03-22 08:58:45 +0000
committerbp <bp@FreeBSD.org>2001-03-22 08:58:45 +0000
commitf7296b2bbabd0414265be30c22ca25d2ef33ac6e (patch)
treebbe0693a6c6906ced11c4ca1229b853358437b7e /sys/kern/kern_linker.c
parent14549fec64f5181cacfbb1f0f3b1fd3f8a0c2ae4 (diff)
downloadFreeBSD-src-f7296b2bbabd0414265be30c22ca25d2ef33ac6e.zip
FreeBSD-src-f7296b2bbabd0414265be30c22ca25d2ef33ac6e.tar.gz
o Actually extract version of interface and store it along with the name.
o Add new parameter to the modlist_lookup() function to perform lookups with strict version matching. o Collapse duplicate code to function(s).
Diffstat (limited to 'sys/kern/kern_linker.c')
-rw-r--r--sys/kern/kern_linker.c151
1 files changed, 99 insertions, 52 deletions
diff --git a/sys/kern/kern_linker.c b/sys/kern/kern_linker.c
index 4911212..e8cfb56 100644
--- a/sys/kern/kern_linker.c
+++ b/sys/kern/kern_linker.c
@@ -69,6 +69,7 @@ struct modlist {
TAILQ_ENTRY(modlist) link; /* chain together all modules */
linker_file_t container;
const char *name;
+ int version;
};
typedef struct modlist *modlist_t;
static modlisthead_t found_modules;
@@ -917,17 +918,33 @@ out:
*/
static modlist_t
-modlist_lookup(const char *name)
+modlist_lookup(const char *name, int ver)
{
modlist_t mod;
TAILQ_FOREACH(mod, &found_modules, link) {
- if (!strcmp(mod->name, name))
+ if (strcmp(mod->name, name) == 0 && (ver == 0 || mod->version == ver))
return mod;
}
return NULL;
}
+static modlist_t
+modlist_newmodule(char *modname, int version, linker_file_t container)
+{
+ modlist_t mod;
+
+ mod = malloc(sizeof(struct modlist), M_LINKER, M_NOWAIT);
+ if (mod == NULL)
+ panic("no memory for module list");
+ bzero(mod, sizeof(*mod));
+ mod->container = container;
+ mod->name = modname;
+ mod->version = version;
+ TAILQ_INSERT_TAIL(&found_modules, mod, link);
+ return mod;
+}
+
/*
* This routine is cheap and nasty but will work for data pointers.
*/
@@ -937,6 +954,65 @@ linker_reloc_ptr(linker_file_t lf, void *offset)
return lf->address + (uintptr_t)offset;
}
+/*
+ * Dereference MDT_VERSION metadata into module name and version
+ */
+static void
+linker_mdt_version(linker_file_t lf, struct mod_metadata *mp,
+ char **modname, int *version)
+{
+ struct mod_version *mvp;
+
+ if (modname)
+ *modname = linker_reloc_ptr(lf, mp->md_cval);
+ if (version) {
+ mvp = linker_reloc_ptr(lf, mp->md_data);
+ *version = mvp->mv_version;
+ }
+}
+
+/*
+ * Dereference MDT_DEPEND metadata into module name and mod_depend structure
+ */
+static void
+linker_mdt_depend(linker_file_t lf, struct mod_metadata *mp,
+ char **modname, struct mod_depend **verinfo)
+{
+
+ if (modname)
+ *modname = linker_reloc_ptr(lf, mp->md_cval);
+ if (verinfo)
+ *verinfo = linker_reloc_ptr(lf, mp->md_data);
+}
+
+static void
+linker_addmodules(linker_file_t lf, struct linker_set *deps, int preload)
+{
+ struct mod_metadata *mp;
+ char *modname;
+ int i, ver;
+
+ for (i = 0; i < deps->ls_length; i++) {
+ if (preload)
+ mp = deps->ls_items[i];
+ else
+ mp = linker_reloc_ptr(lf, deps->ls_items[i]);
+ if (mp->md_type != MDT_VERSION)
+ continue;
+ if (preload) {
+ modname = mp->md_cval;
+ ver = ((struct mod_version*)mp->md_data)->mv_version;
+ } else
+ linker_mdt_version(lf, mp, &modname, &ver);
+ if (modlist_lookup(modname, ver) != NULL) {
+ printf("module %s already present!\n", modname);
+ /* XXX what can we do? this is a build error. :-( */
+ continue;
+ }
+ modlist_newmodule(modname, ver, lf);
+ }
+}
+
static void
linker_preload(void* arg)
{
@@ -951,7 +1027,8 @@ linker_preload(void* arg)
linker_file_list_t depended_files;
struct linker_set *deps;
struct mod_metadata *mp, *nmp;
- int i, j;
+ struct mod_depend *verinfo;
+ int i, j, nver;
int resolves;
modlist_t mod;
@@ -990,25 +1067,8 @@ linker_preload(void* arg)
*/
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|M_ZERO);
- if (mod == NULL)
- panic("no memory for module list");
- mod->container = linker_kernel_file;
- mod->name = modname;
- TAILQ_INSERT_TAIL(&found_modules, mod, link);
- }
- }
+ if (deps)
+ linker_addmodules(linker_kernel_file, deps, 1);
/*
* this is a once-off kinky bubble sort
@@ -1027,18 +1087,19 @@ restart:
mp = linker_reloc_ptr(lf, deps->ls_items[i]);
if (mp->md_type != MDT_DEPEND)
continue;
- modname = linker_reloc_ptr(lf, mp->md_cval);
+ linker_mdt_depend(lf, mp, &modname, &verinfo);
for (j = 0; j < deps->ls_length; j++) {
nmp = linker_reloc_ptr(lf, deps->ls_items[j]);
if (nmp->md_type != MDT_VERSION)
continue;
+ linker_mdt_version(lf, nmp, &nmodname, NULL);
nmodname = linker_reloc_ptr(lf, nmp->md_cval);
if (strcmp(modname, nmodname) == 0)
break;
}
if (j < deps->ls_length) /* it's a self reference */
continue;
- if (modlist_lookup(modname) == NULL) {
+ if (modlist_lookup(modname, 0) == NULL) {
/* ok, the module isn't here yet, we are not finished */
resolves = 0;
}
@@ -1054,20 +1115,14 @@ restart:
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) {
+ linker_mdt_version(lf, mp, &modname, &nver);
+ if (modlist_lookup(modname, nver) != 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|M_ZERO);
- if (mod == NULL)
- panic("no memory for module list");
- mod->container = lf;
- mod->name = modname;
- TAILQ_INSERT_TAIL(&found_modules, mod, link);
+ modlist_newmodule(modname, nver, lf);
}
}
TAILQ_REMOVE(&loaded_files, lf, loaded);
@@ -1108,8 +1163,8 @@ restart:
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);
+ linker_mdt_depend(lf, mp, &modname, &verinfo);
+ mod = modlist_lookup(modname, 0);
mod->container->refs++;
error = linker_file_add_dependancy(lf, mod->container);
if (error)
@@ -1299,7 +1354,7 @@ linker_load_dependancies(linker_file_t lf)
struct mod_metadata *mp, *nmp;
modlist_t mod;
char *modname, *nmodname;
- int i, j, error = 0;
+ int i, j, ver, error = 0;
/*
* All files are dependant on /kernel.
@@ -1319,12 +1374,15 @@ linker_load_dependancies(linker_file_t lf)
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_mdt_version(lf, mp, &modname, &ver);
+ mod = modlist_lookup(modname, ver);
+ if (mod != NULL) {
+ printf("interface %s.%d already present in the KLD '%s'!\n",
+ modname, ver, mod->container->filename);
return EEXIST;
}
}
+
for (i = 0; i < deps->ls_length; i++) {
mp = linker_reloc_ptr(lf, deps->ls_items[i]);
if (mp->md_type != MDT_DEPEND)
@@ -1341,7 +1399,7 @@ linker_load_dependancies(linker_file_t lf)
}
if (j < deps->ls_length) /* early exit, it's a self reference */
continue;
- mod = modlist_lookup(modname);
+ mod = modlist_lookup(modname, 0);
if (mod) { /* woohoo, it's loaded already */
lfdep = mod->container;
lfdep->refs++;
@@ -1360,17 +1418,6 @@ linker_load_dependancies(linker_file_t lf)
if (error)
return error;
- 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|M_ZERO);
- if (mod == NULL)
- panic("no memory for module list");
- mod->container = lf;
- mod->name = modname;
- TAILQ_INSERT_TAIL(&found_modules, mod, link);
- }
+ linker_addmodules(lf, deps, 0);
return error;
}
OpenPOWER on IntegriCloud