summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/kern/kern_linker.c80
-rw-r--r--sys/kern/link_aout.c146
-rw-r--r--sys/kern/link_elf.c361
-rw-r--r--sys/kern/link_elf_obj.c361
-rw-r--r--sys/kern/linker_if.m75
-rw-r--r--sys/sys/linker.h57
6 files changed, 635 insertions, 445 deletions
diff --git a/sys/kern/kern_linker.c b/sys/kern/kern_linker.c
index 13a2491..a3193e5 100644
--- a/sys/kern/kern_linker.c
+++ b/sys/kern/kern_linker.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1997 Doug Rabson
+ * Copyright (c) 1997-2000 Doug Rabson
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -46,6 +46,8 @@
#include <vm/vm_zone.h>
+#include "linker_if.h"
+
#ifdef KLD_DEBUG
int kld_debug = 0;
#endif
@@ -59,6 +61,16 @@ static linker_class_list_t classes;
static linker_file_list_t linker_files;
static int next_file_id = 1;
+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);
+}
+
static void
linker_init(void* arg)
{
@@ -70,21 +82,10 @@ linker_init(void* arg)
SYSINIT(linker, SI_SUB_KLD, SI_ORDER_FIRST, linker_init, 0);
int
-linker_add_class(const char* desc, void* priv,
- struct linker_class_ops* ops)
+linker_add_class(linker_class_t lc)
{
- linker_class_t lc;
-
- lc = malloc(sizeof(struct linker_class), M_LINKER, M_NOWAIT);
- if (!lc)
- return ENOMEM;
- bzero(lc, sizeof(*lc));
-
- lc->desc = desc;
- lc->priv = priv;
- lc->ops = ops;
+ kobj_class_compile((kobj_class_t) lc);
TAILQ_INSERT_HEAD(&classes, lc, link);
-
return 0;
}
@@ -267,9 +268,9 @@ linker_load_file(const char* filename, linker_file_t* result)
KLD_DPF(FILE, ("linker_load_file: trying to load %s as %s\n",
filename, lc->desc));
- error = lc->ops->load_file(koname, &lf); /* First with .ko */
+ error = LINKER_LOAD_FILE(lc, koname, &lf); /* First with .ko */
if (lf == NULL && error == ENOENT)
- error = lc->ops->load_file(filename, &lf); /* Then try without */
+ error = LINKER_LOAD_FILE(lc, filename, &lf); /* Then try without */
/*
* If we got something other than ENOENT, then it exists but we cannot
* load it for some other reason.
@@ -341,10 +342,9 @@ linker_find_file_by_id(int fileid)
}
linker_file_t
-linker_make_file(const char* pathname, void* priv, struct linker_file_ops* ops)
+linker_make_file(const char* pathname, linker_class_t lc)
{
linker_file_t lf = 0;
- int namelen;
const char *filename;
filename = rindex(pathname, '/');
@@ -355,25 +355,20 @@ linker_make_file(const char* pathname, void* priv, struct linker_file_ops* ops)
KLD_DPF(FILE, ("linker_make_file: new file, filename=%s\n", filename));
lockmgr(&lock, LK_EXCLUSIVE, 0, curproc);
- namelen = strlen(filename) + 1;
- lf = malloc(sizeof(struct linker_file) + namelen, M_LINKER, M_WAITOK);
+ lf = (linker_file_t) kobj_create((kobj_class_t) lc, M_LINKER, M_WAITOK);
if (!lf)
goto out;
- bzero(lf, sizeof(*lf));
lf->refs = 1;
lf->userrefs = 0;
lf->flags = 0;
- lf->filename = (char*) (lf + 1);
- strcpy(lf->filename, filename);
+ lf->filename = linker_strdup(filename);
lf->id = next_file_id++;
lf->ndeps = 0;
lf->deps = NULL;
STAILQ_INIT(&lf->common);
TAILQ_INIT(&lf->modules);
- lf->priv = priv;
- lf->ops = ops;
TAILQ_INSERT_TAIL(&linker_files, lf, link);
out:
@@ -438,8 +433,9 @@ linker_file_unload(linker_file_t file)
free(cp, M_LINKER);
}
- file->ops->unload(file);
- free(file, M_LINKER);
+ LINKER_UNLOAD(file);
+ free(file->filename, M_LINKER);
+ kobj_delete((kobj_t) file, M_LINKER);
out:
return error;
@@ -480,8 +476,8 @@ linker_file_lookup_symbol(linker_file_t file, const char* name, int deps)
KLD_DPF(SYM, ("linker_file_lookup_symbol: file=%x, name=%s, deps=%d\n",
file, name, deps));
- if (file->ops->lookup_symbol(file, name, &sym) == 0) {
- file->ops->symbol_values(file, sym, &symval);
+ if (LINKER_LOOKUP_SYMBOL(file, name, &sym) == 0) {
+ LINKER_SYMBOL_VALUES(file, sym, &symval);
if (symval.value == 0)
/*
* For commons, first look them up in the dependancies and
@@ -581,7 +577,7 @@ linker_ddb_lookup(const char *symstr, c_linker_sym_t *sym)
linker_file_t lf;
for (lf = TAILQ_FIRST(&linker_files); lf; lf = TAILQ_NEXT(lf, link)) {
- if (lf->ops->lookup_symbol(lf, symstr, sym) == 0)
+ if (LINKER_LOOKUP_SYMBOL(lf, symstr, sym) == 0)
return 0;
}
return ENOENT;
@@ -599,7 +595,7 @@ linker_ddb_search_symbol(caddr_t value, c_linker_sym_t *sym, long *diffp)
best = 0;
bestdiff = off;
for (lf = TAILQ_FIRST(&linker_files); lf; lf = TAILQ_NEXT(lf, link)) {
- if (lf->ops->search_symbol(lf, value, &es, &diff) != 0)
+ if (LINKER_SEARCH_SYMBOL(lf, value, &es, &diff) != 0)
continue;
if (es != 0 && diff < bestdiff) {
best = es;
@@ -625,7 +621,7 @@ linker_ddb_symbol_values(c_linker_sym_t sym, linker_symval_t *symval)
linker_file_t lf;
for (lf = TAILQ_FIRST(&linker_files); lf; lf = TAILQ_NEXT(lf, link)) {
- if (lf->ops->symbol_values(lf, sym, symval) == 0)
+ if (LINKER_SYMBOL_VALUES(lf, sym, symval) == 0)
return 0;
}
return ENOENT;
@@ -857,8 +853,8 @@ kldsym(struct proc *p, struct kldsym_args *uap)
error = ENOENT;
goto out;
}
- if (lf->ops->lookup_symbol(lf, symstr, &sym) == 0 &&
- lf->ops->symbol_values(lf, sym, &symval) == 0) {
+ if (LINKER_LOOKUP_SYMBOL(lf, symstr, &sym) == 0 &&
+ LINKER_SYMBOL_VALUES(lf, sym, &symval) == 0) {
lookup.symvalue = (uintptr_t)symval.value;
lookup.symsize = symval.size;
error = copyout(&lookup, SCARG(uap, data), sizeof(lookup));
@@ -866,8 +862,8 @@ kldsym(struct proc *p, struct kldsym_args *uap)
error = ENOENT;
} else {
for (lf = TAILQ_FIRST(&linker_files); lf; lf = TAILQ_NEXT(lf, link)) {
- if (lf->ops->lookup_symbol(lf, symstr, &sym) == 0 &&
- lf->ops->symbol_values(lf, sym, &symval) == 0) {
+ if (LINKER_LOOKUP_SYMBOL(lf, symstr, &sym) == 0 &&
+ LINKER_SYMBOL_VALUES(lf, sym, &symval) == 0) {
lookup.symvalue = (uintptr_t)symval.value;
lookup.symsize = symval.size;
error = copyout(&lookup, SCARG(uap, data), sizeof(lookup));
@@ -920,7 +916,7 @@ linker_preload(void* arg)
}
lf = NULL;
for (lc = TAILQ_FIRST(&classes); lc; lc = TAILQ_NEXT(lc, link)) {
- error = lc->ops->load_file(modname, &lf);
+ error = LINKER_LOAD_FILE(lc, modname, &lf);
if (error) {
lf = NULL;
break;
@@ -975,16 +971,6 @@ 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");
-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);
-}
-
char *
linker_search_path(const char *name)
{
diff --git a/sys/kern/link_aout.c b/sys/kern/link_aout.c
index de5518d..f9b55e5 100644
--- a/sys/kern/link_aout.c
+++ b/sys/kern/link_aout.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1997 Doug Rabson
+ * Copyright (c) 1997-2000 Doug Rabson
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -42,6 +42,8 @@
#include <vm/vm_zone.h>
+#include "linker_if.h"
+
#ifndef __ELF__
#include <vm/vm.h>
#include <vm/pmap.h>
@@ -51,7 +53,15 @@
#include <a.out.h>
#include <link.h>
-static int link_aout_load_module(const char*, linker_file_t*);
+typedef struct aout_file {
+ struct linker_file lf; /* Common fields */
+ int preloaded; /* Was this pre-loader */
+ char* address; /* Load address */
+ 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*);
@@ -64,30 +74,21 @@ static int link_aout_search_symbol(linker_file_t lf, caddr_t value,
static void link_aout_unload_file(linker_file_t);
static void link_aout_unload_module(linker_file_t);
-static struct linker_class_ops link_aout_class_ops = {
- link_aout_load_module,
+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),
+ { 0, 0 }
};
-static struct linker_file_ops link_aout_file_ops = {
- link_aout_lookup_symbol,
- link_aout_symbol_values,
- link_aout_search_symbol,
- link_aout_unload_file,
+static struct linker_class link_aout_class = {
+ "a.out", link_aout_methods, sizeof(struct aout_file)
};
-static struct linker_file_ops link_aout_module_ops = {
- link_aout_lookup_symbol,
- link_aout_symbol_values,
- link_aout_search_symbol,
- link_aout_unload_module,
-};
-
-typedef struct aout_file {
- char* address; /* Load address */
- struct _dynamic* dynamic; /* Symbol table etc. */
-} *aout_file_t;
-static int load_dependancies(linker_file_t lf);
-static int relocate_file(linker_file_t lf);
+static int load_dependancies(aout_file_t af);
+static int relocate_file(aout_file_t af);
/*
* The kernel symbol table starts here.
@@ -101,23 +102,19 @@ link_aout_init(void* arg)
struct _dynamic* dp = &_DYNAMIC;
#endif
- linker_add_class("a.out", NULL, &link_aout_class_ops);
+ linker_add_class(&link_aout_class);
#ifndef __ELF__
if (dp) {
aout_file_t af;
- af = malloc(sizeof(struct aout_file), M_LINKER, M_NOWAIT);
- if (af == NULL)
- panic("link_aout_init: Can't create linker structures for kernel");
- bzero(af, sizeof(*af));
-
- af->address = 0;
- af->dynamic = dp;
linker_kernel_file =
- linker_make_file(kernelname, af, &link_aout_file_ops);
+ linker_make_file(kernelname, af, &link_aout_class);
if (linker_kernel_file == NULL)
panic("link_aout_init: Can't create linker structures for kernel");
+ af = (aout_file_t) linker_kernel_file;
+ af->address = 0;
+ 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;
@@ -129,7 +126,8 @@ link_aout_init(void* arg)
SYSINIT(link_aout, SI_SUB_KLD, SI_ORDER_THIRD, link_aout_init, 0);
static int
-link_aout_load_module(const char* filename, linker_file_t* result)
+link_aout_load_module(linker_class_t lc,
+ const char* filename, linker_file_t* result)
{
caddr_t modptr, baseptr;
char *type;
@@ -149,32 +147,32 @@ link_aout_load_module(const char* filename, linker_file_t* result)
((ehdr = (struct exec *)preload_search_info(modptr, MODINFO_METADATA | MODINFOMD_AOUTEXEC)) == NULL))
return(0); /* we can't handle this */
+ /* Register with kld */
+ lf = linker_make_file(filename, &link_aout_class);
+ if (lf == NULL) {
+ return(ENOMEM);
+ }
+ af = (aout_file_t) lf;
+
/* Looks like we can handle this one */
- af = malloc(sizeof(struct aout_file), M_LINKER, M_WAITOK);
- bzero(af, sizeof(*af));
+ af->preloaded = 1;
af->address = baseptr;
/* Assume _DYNAMIC is the first data item. */
af->dynamic = (struct _dynamic*)(af->address + ehdr->a_text);
if (af->dynamic->d_version != LD_VERSION_BSD) {
- free(af, M_LINKER);
+ linker_file_unload(lf);
return(0); /* we can't handle this */
}
af->dynamic->d_un.d_sdt = (struct section_dispatch_table *)
((char *)af->dynamic->d_un.d_sdt + (vm_offset_t)af->address);
- /* Register with kld */
- lf = linker_make_file(filename, af, &link_aout_module_ops);
- if (lf == NULL) {
- free(af, M_LINKER);
- return(ENOMEM);
- }
lf->address = af->address;
lf->size = ehdr->a_text + ehdr->a_data + ehdr->a_bss;
/* Try to load dependancies */
- if (((error = load_dependancies(lf)) != 0) ||
- ((error = relocate_file(lf)) != 0)) {
+ if (((error = load_dependancies(af)) != 0) ||
+ ((error = relocate_file(af)) != 0)) {
linker_file_unload(lf);
return(error);
}
@@ -192,7 +190,7 @@ link_aout_load_file(const char* filename, linker_file_t* result)
int resid;
struct exec header;
aout_file_t af;
- linker_file_t lf;
+ linker_file_t lf = 0;
char *pathname;
pathname = linker_search_path(filename);
@@ -219,8 +217,13 @@ link_aout_load_file(const char* filename, linker_file_t* result)
/*
* We have an a.out file, so make some space to read it in.
*/
- af = malloc(sizeof(struct aout_file), M_LINKER, M_WAITOK);
- bzero(af, sizeof(*af));
+ lf = linker_make_file(filename, &link_aout_class);
+ if (lf == NULL) {
+ error = ENOMEM;
+ goto out;
+ }
+
+ af = (aout_file_t) lf;
af->address = malloc(header.a_text + header.a_data + header.a_bss,
M_LINKER, M_WAITOK);
@@ -239,26 +242,17 @@ link_aout_load_file(const char* filename, linker_file_t* result)
*/
af->dynamic = (struct _dynamic*) (af->address + header.a_text);
if (af->dynamic->d_version != LD_VERSION_BSD) {
- free(af->address, M_LINKER);
- free(af, M_LINKER);
+ error = ENOEXEC;
goto out;
}
af->dynamic->d_un.d_sdt = (struct section_dispatch_table *)
((char *)af->dynamic->d_un.d_sdt + (vm_offset_t)af->address);
- lf = linker_make_file(filename, af, &link_aout_file_ops);
- if (lf == NULL) {
- free(af->address, M_LINKER);
- free(af, M_LINKER);
- error = ENOMEM;
- goto out;
- }
lf->address = af->address;
lf->size = header.a_text + header.a_data + header.a_bss;
- if ((error = load_dependancies(lf)) != 0
- || (error = relocate_file(lf)) != 0) {
- linker_file_unload(lf);
+ if ((error = load_dependancies(af)) != 0
+ || (error = relocate_file(af)) != 0) {
goto out;
}
@@ -266,6 +260,8 @@ link_aout_load_file(const char* filename, linker_file_t* result)
*result = lf;
out:
+ if (error && lf)
+ linker_file_unload(lf);
VOP_UNLOCK(nd.ni_vp, 0, p);
vn_close(nd.ni_vp, FREAD, p->p_ucred, p);
@@ -275,22 +271,20 @@ out:
static void
link_aout_unload_file(linker_file_t file)
{
- aout_file_t af = file->priv;
+ aout_file_t af = (aout_file_t) file;
- if (af) {
- if (af->address)
- free(af->address, M_LINKER);
- free(af, M_LINKER);
+ if (af->preloaded) {
+ link_aout_unload_module(file);
+ return;
}
+
+ if (af->address)
+ free(af->address, M_LINKER);
}
static void
link_aout_unload_module(linker_file_t file)
{
- aout_file_t af = file->priv;
-
- if (af)
- free(af, M_LINKER);
if (file->filename)
preload_delete_name(file->filename);
}
@@ -298,9 +292,8 @@ link_aout_unload_module(linker_file_t file)
#define AOUT_RELOC(af, type, off) (type*) ((af)->address + (off))
static int
-load_dependancies(linker_file_t lf)
+load_dependancies(aout_file_t af)
{
- aout_file_t af = lf->priv;
linker_file_t lfdep;
long off;
struct sod* sodp;
@@ -313,7 +306,7 @@ load_dependancies(linker_file_t lf)
*/
if (linker_kernel_file) {
linker_kernel_file->refs++;
- linker_file_add_dependancy(lf, linker_kernel_file);
+ linker_file_add_dependancy(&af->lf, linker_kernel_file);
}
off = LD_NEED(af->dynamic);
@@ -328,7 +321,7 @@ load_dependancies(linker_file_t lf)
error = linker_load_file(name, &lfdep);
if (error)
goto out;
- error = linker_file_add_dependancy(lf, lfdep);
+ error = linker_file_add_dependancy(&af->lf, lfdep);
if (error)
goto out;
off = sodp->sod_next;
@@ -373,9 +366,8 @@ write_relocation(struct relocation_info* r, char* addr, long value)
}
static int
-relocate_file(linker_file_t lf)
+relocate_file(aout_file_t af)
{
- aout_file_t af = lf->priv;
struct relocation_info* rel;
struct relocation_info* erel;
struct relocation_info* r;
@@ -407,7 +399,7 @@ relocate_file(linker_file_t lf)
relocation = 0;
} else
relocation = (intptr_t)
- linker_file_lookup_symbol(lf, sym + 1,
+ linker_file_lookup_symbol(&af->lf, sym + 1,
np->nz_type != (N_SETV+N_EXT));
if (!relocation) {
printf("link_aout: symbol %s not found\n", sym);
@@ -457,7 +449,7 @@ int
link_aout_lookup_symbol(linker_file_t file, const char* name,
c_linker_sym_t* sym)
{
- aout_file_t af = file->priv;
+ aout_file_t af = (aout_file_t) file;
long hashval;
struct rrs_hash* hashbase;
struct nzlist* symbolbase;
@@ -530,7 +522,7 @@ static int
link_aout_symbol_values(linker_file_t file, c_linker_sym_t sym,
linker_symval_t* symval)
{
- aout_file_t af = file->priv;
+ aout_file_t af = (aout_file_t) file;
const struct nzlist* np = (const struct nzlist*) sym;
char* stringbase;
long numsym = LD_STABSZ(af->dynamic) / sizeof(struct nzlist);
@@ -560,7 +552,7 @@ static int
link_aout_search_symbol(linker_file_t lf, caddr_t value,
c_linker_sym_t* sym, long* diffp)
{
- aout_file_t af = lf->priv;
+ aout_file_t af = (aout_file_t) lf;
u_long off = (uintptr_t) (void *) value;
u_long diff = off;
u_long sp_nz_value;
diff --git a/sys/kern/link_elf.c b/sys/kern/link_elf.c
index daf3b30..27d39de 100644
--- a/sys/kern/link_elf.c
+++ b/sys/kern/link_elf.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1998 Doug Rabson
+ * Copyright (c) 1998-2000 Doug Rabson
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -26,6 +26,8 @@
* $FreeBSD$
*/
+#include "opt_ddb.h"
+
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/systm.h>
@@ -48,41 +50,18 @@
#endif
#include <vm/pmap.h>
#include <vm/vm_map.h>
+#include <link.h>
-static int link_elf_load_module(const char*, linker_file_t*);
-static int link_elf_load_file(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*);
-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 struct linker_class_ops link_elf_class_ops = {
- link_elf_load_module,
-};
-
-static struct linker_file_ops link_elf_file_ops = {
- link_elf_lookup_symbol,
- link_elf_symbol_values,
- link_elf_search_symbol,
- link_elf_unload_file,
-};
+#include "linker_if.h"
-static struct linker_file_ops link_elf_module_ops = {
- link_elf_lookup_symbol,
- link_elf_symbol_values,
- link_elf_search_symbol,
- link_elf_unload_module,
-};
typedef struct elf_file {
+ struct linker_file lf; /* Common fields */
+ int preloaded; /* Was file pre-loaded */
caddr_t address; /* Relocation address */
#ifdef SPARSE_MAPPING
vm_object_t object; /* VM object to hold file pages */
#endif
- const Elf_Dyn* dynamic; /* Symbol table etc. */
+ Elf_Dyn* dynamic; /* Symbol table etc. */
Elf_Off nbuckets; /* DT_HASH info */
Elf_Off nchains;
const Elf_Off* buckets;
@@ -107,12 +86,64 @@ typedef struct elf_file {
long ddbstrcnt; /* number of bytes in string table */
caddr_t symbase; /* malloc'ed symbold base */
caddr_t strbase; /* malloc'ed string base */
+#ifdef DDB
+ struct link_map gdb; /* hooks for gdb */
+#endif
} *elf_file_t;
-static int parse_dynamic(linker_file_t lf);
-static int load_dependancies(linker_file_t lf);
-static int relocate_file(linker_file_t lf);
-static int parse_module_symbols(linker_file_t lf);
+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_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*);
+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 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),
+ { 0, 0 }
+};
+
+static struct linker_class link_elf_class = {
+#if ELF_TARG_CLASS == ELFCLASS32
+ "elf32",
+#else
+ "elf64",
+#endif
+ link_elf_methods, sizeof(struct elf_file)
+};
+
+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);
+
+#ifdef DDB
+
+/*
+ * A list of loaded modules for GDB to use for loading symbols.
+ */
+struct r_debug r_debug;
+
+#define GDB_STATE(s) r_debug.r_state = s; r_debug_state();
+
+/*
+ * Function for the debugger to set a breakpoint on to gain control.
+ */
+void
+r_debug_state(void)
+{
+}
+
+#endif
/*
* The kernel symbol table starts here.
@@ -129,35 +160,29 @@ link_elf_init(void* arg)
char *modname;
#endif
-#if ELF_TARG_CLASS == ELFCLASS32
- linker_add_class("elf32", NULL, &link_elf_class_ops);
-#else
- linker_add_class("elf64", NULL, &link_elf_class_ops);
-#endif
+ linker_add_class(&link_elf_class);
#ifdef __ELF__
dp = (Elf_Dyn*) &_DYNAMIC;
if (dp) {
- ef = malloc(sizeof(struct elf_file), M_LINKER, M_NOWAIT);
- if (ef == NULL)
- panic("link_elf_init: Can't create linker structures for kernel");
- bzero(ef, sizeof(*ef));
-
- ef->address = 0;
-#ifdef SPARSE_MAPPING
- ef->object = 0;
-#endif
- ef->dynamic = dp;
modname = NULL;
modptr = preload_search_by_type("elf kernel");
if (modptr)
modname = (char *)preload_search_info(modptr, MODINFO_NAME);
if (modname == NULL)
modname = "kernel";
- linker_kernel_file = linker_make_file(modname, ef, &link_elf_file_ops);
+ linker_kernel_file = linker_make_file(modname, &link_elf_class);
if (linker_kernel_file == NULL)
panic("link_elf_init: Can't create linker structures for kernel");
- parse_dynamic(linker_kernel_file);
+
+ ef = (elf_file_t) linker_kernel_file;
+ ef->address = 0;
+#ifdef SPARSE_MAPPING
+ ef->object = 0;
+#endif
+ ef->dynamic = dp;
+
+ parse_dynamic(ef);
linker_kernel_file->address = (caddr_t) KERNBASE;
linker_kernel_file->size = -(intptr_t)linker_kernel_file->address;
@@ -170,9 +195,24 @@ link_elf_init(void* arg)
if (sizeptr)
linker_kernel_file->size = *(size_t *)sizeptr;
}
- (void)parse_module_symbols(linker_kernel_file);
+ (void)parse_module_symbols(ef);
linker_current_file = linker_kernel_file;
linker_kernel_file->flags |= LINKER_FILE_LINKED;
+
+#ifdef DDB
+ ef->gdb.l_addr = linker_kernel_file->address;
+ ef->gdb.l_name = modname;
+ ef->gdb.l_ld = dp;
+ ef->gdb.l_prev = 0;
+ ef->gdb.l_next = 0;
+
+ r_debug.r_map = &ef->gdb;
+ r_debug.r_brk = r_debug_state;
+ r_debug.r_state = RT_CONSISTENT;
+
+ r_debug_state(); /* say hello to gdb! */
+#endif
+
}
#endif
}
@@ -180,9 +220,8 @@ link_elf_init(void* arg)
SYSINIT(link_elf, SI_SUB_KLD, SI_ORDER_SECOND, link_elf_init, 0);
static int
-parse_module_symbols(linker_file_t lf)
+parse_module_symbols(elf_file_t ef)
{
- elf_file_t ef = lf->priv;
caddr_t pointer;
caddr_t ssym, esym, base;
caddr_t strtab;
@@ -232,10 +271,9 @@ parse_module_symbols(linker_file_t lf)
}
static int
-parse_dynamic(linker_file_t lf)
+parse_dynamic(elf_file_t ef)
{
- elf_file_t ef = lf->priv;
- const Elf_Dyn *dp;
+ Elf_Dyn *dp;
int plttype = DT_REL;
for (dp = ef->dynamic; dp->d_tag != DT_NULL; dp++) {
@@ -298,6 +336,11 @@ parse_dynamic(linker_file_t lf)
if (plttype != DT_REL && plttype != DT_RELA)
return ENOEXEC;
break;
+#ifdef DDB
+ case DT_DEBUG:
+ dp->d_un.d_ptr = (Elf_Addr) &r_debug;
+ break;
+#endif
}
}
@@ -322,8 +365,43 @@ link_elf_error(const char *s)
printf("kldload: %s\n", s);
}
+#ifdef DDB
+
+static void
+link_elf_add_gdb(struct link_map *l)
+{
+ struct link_map *prev;
+
+ /*
+ * Scan to the end of the list.
+ */
+ for (prev = r_debug.r_map; prev->l_next != NULL; prev = prev->l_next)
+ ;
+
+ /* Link in the new entry. */
+ l->l_prev = prev;
+ l->l_next = prev->l_next;
+ prev->l_next = l;
+}
+
+static void
+link_elf_delete_gdb(struct link_map *l)
+{
+ if (l->l_prev == NULL) {
+ if ((r_debug.r_map = l->l_next) != NULL)
+ l->l_next->l_prev = NULL;
+ return;
+ }
+
+ if ((l->l_prev->l_next = l->l_next) != NULL)
+ l->l_next->l_prev = l->l_prev;
+}
+
+#endif /* DDB */
+
static int
-link_elf_load_module(const char *filename, linker_file_t *result)
+link_elf_load_module(linker_class_t cls,
+ const char *filename, linker_file_t *result)
{
caddr_t modptr, baseptr, sizeptr, dynptr;
char *type;
@@ -347,10 +425,13 @@ link_elf_load_module(const char *filename, linker_file_t *result)
if (baseptr == NULL || sizeptr == NULL || dynptr == NULL)
return (EINVAL);
- ef = malloc(sizeof(struct elf_file), M_LINKER, M_WAITOK);
- if (ef == NULL)
- return (ENOMEM);
- bzero(ef, sizeof(*ef));
+ lf = linker_make_file(filename, &link_elf_class);
+ if (lf == NULL) {
+ return ENOMEM;
+ }
+
+ ef = (elf_file_t) lf;
+ ef->preloaded = 1;
ef->modptr = modptr;
ef->address = *(caddr_t *)baseptr;
#ifdef SPARSE_MAPPING
@@ -358,31 +439,37 @@ link_elf_load_module(const char *filename, linker_file_t *result)
#endif
dp = (vm_offset_t)ef->address + *(vm_offset_t *)dynptr;
ef->dynamic = (Elf_Dyn *)dp;
- lf = linker_make_file(filename, ef, &link_elf_module_ops);
- if (lf == NULL) {
- free(ef, M_LINKER);
- return ENOMEM;
- }
+
lf->address = ef->address;
lf->size = *(size_t *)sizeptr;
- error = parse_dynamic(lf);
+ error = parse_dynamic(ef);
if (error) {
linker_file_unload(lf);
return error;
}
- error = load_dependancies(lf);
+ error = load_dependancies(ef);
if (error) {
linker_file_unload(lf);
return error;
}
- error = relocate_file(lf);
+ error = relocate_file(ef);
if (error) {
linker_file_unload(lf);
return error;
}
- (void)parse_module_symbols(lf);
+ (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);
}
@@ -534,8 +621,13 @@ link_elf_load_file(const char* filename, linker_file_t* result)
base_vlimit = round_page(segs[1]->p_vaddr + segs[1]->p_memsz);
mapsize = base_vlimit - base_vaddr;
- ef = malloc(sizeof(struct elf_file), M_LINKER, M_WAITOK);
- bzero(ef, sizeof(*ef));
+ lf = linker_make_file(filename, &link_elf_class);
+ if (!lf) {
+ error = ENOMEM;
+ goto out;
+ }
+
+ ef = (elf_file_t) lf;
#ifdef SPARSE_MAPPING
ef->object = vm_object_allocate(OBJT_DEFAULT, mapsize >> PAGE_SHIFT);
if (ef->object == NULL) {
@@ -551,11 +643,15 @@ link_elf_load_file(const char* filename, linker_file_t* result)
VM_PROT_ALL, VM_PROT_ALL, 0);
if (error) {
vm_object_deallocate(ef->object);
- free(ef, M_LINKER);
+ ef->object = 0;
goto out;
}
#else
ef->address = malloc(mapsize, M_LINKER, M_WAITOK);
+ if (!ef->address) {
+ error = ENOMEM;
+ goto out;
+ }
#endif
mapbase = ef->address;
@@ -568,15 +664,6 @@ link_elf_load_file(const char* filename, linker_file_t* result)
segbase, segs[i]->p_filesz, segs[i]->p_offset,
UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, p);
if (error) {
-#ifdef SPARSE_MAPPING
- vm_map_remove(kernel_map, (vm_offset_t) ef->address,
- (vm_offset_t) ef->address
- + (ef->object->size << PAGE_SHIFT));
- vm_object_deallocate(ef->object);
-#else
- free(ef->address, M_LINKER);
-#endif
- free(ef, M_LINKER);
goto out;
}
bzero(segbase + segs[i]->p_filesz,
@@ -593,32 +680,18 @@ link_elf_load_file(const char* filename, linker_file_t* result)
#endif
}
- ef->dynamic = (const Elf_Dyn *) (mapbase + phdyn->p_vaddr - base_vaddr);
+ ef->dynamic = (Elf_Dyn *) (mapbase + phdyn->p_vaddr - base_vaddr);
- lf = linker_make_file(filename, ef, &link_elf_file_ops);
- if (lf == NULL) {
-#ifdef SPARSE_MAPPING
- vm_map_remove(kernel_map, (vm_offset_t) ef->address,
- (vm_offset_t) ef->address
- + (ef->object->size << PAGE_SHIFT));
- vm_object_deallocate(ef->object);
-#else
- free(ef->address, M_LINKER);
-#endif
- free(ef, M_LINKER);
- error = ENOMEM;
- goto out;
- }
lf->address = ef->address;
lf->size = mapsize;
- error = parse_dynamic(lf);
+ error = parse_dynamic(ef);
if (error)
goto out;
- error = load_dependancies(lf);
+ error = load_dependancies(ef);
if (error)
goto out;
- error = relocate_file(lf);
+ error = relocate_file(ef);
if (error)
goto out;
@@ -675,6 +748,15 @@ link_elf_load_file(const char* filename, linker_file_t* result)
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_ld = ef->dynamic;
+ link_elf_add_gdb(&ef->gdb);
+ GDB_STATE(RT_CONSISTENT);
+#endif
+
nosyms:
*result = lf;
@@ -695,43 +777,49 @@ out:
static void
link_elf_unload_file(linker_file_t file)
{
- elf_file_t ef = file->priv;
+ elf_file_t ef = (elf_file_t) file;
+
+#ifdef DDB
+ if (ef->gdb.l_ld) {
+ 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) {
+ if (ef->preloaded) {
+ link_elf_unload_module(file);
+ return;
+ }
#ifdef SPARSE_MAPPING
- if (ef->object) {
- vm_map_remove(kernel_map, (vm_offset_t) ef->address,
- (vm_offset_t) ef->address
- + (ef->object->size << PAGE_SHIFT));
- vm_object_deallocate(ef->object);
- }
+ if (ef->object) {
+ vm_map_remove(kernel_map, (vm_offset_t) ef->address,
+ (vm_offset_t) ef->address
+ + (ef->object->size << PAGE_SHIFT));
+ vm_object_deallocate(ef->object);
+ }
#else
- if (ef->address)
- free(ef->address, M_LINKER);
+ if (ef->address)
+ free(ef->address, M_LINKER);
#endif
- if (ef->symbase)
- free(ef->symbase, M_LINKER);
- if (ef->strbase)
- free(ef->strbase, M_LINKER);
- free(ef, M_LINKER);
- }
+ if (ef->symbase)
+ free(ef->symbase, M_LINKER);
+ if (ef->strbase)
+ free(ef->strbase, M_LINKER);
}
static void
link_elf_unload_module(linker_file_t file)
{
- elf_file_t ef = file->priv;
-
- if (ef)
- free(ef, M_LINKER);
if (file->filename)
preload_delete_name(file->filename);
}
static int
-load_dependancies(linker_file_t lf)
+load_dependancies(elf_file_t ef)
{
- elf_file_t ef = lf->priv;
linker_file_t lfdep;
char* name;
const Elf_Dyn *dp;
@@ -742,7 +830,7 @@ load_dependancies(linker_file_t lf)
*/
if (linker_kernel_file) {
linker_kernel_file->refs++;
- linker_file_add_dependancy(lf, linker_kernel_file);
+ linker_file_add_dependancy(&ef->lf, linker_kernel_file);
}
for (dp = ef->dynamic; dp->d_tag != DT_NULL; dp++) {
@@ -752,7 +840,7 @@ load_dependancies(linker_file_t lf)
error = linker_load_file(name, &lfdep);
if (error)
goto out;
- error = linker_file_add_dependancy(lf, lfdep);
+ error = linker_file_add_dependancy(&ef->lf, lfdep);
if (error)
goto out;
}
@@ -775,9 +863,8 @@ symbol_name(elf_file_t ef, Elf_Word r_info)
}
static int
-relocate_file(linker_file_t lf)
+relocate_file(elf_file_t ef)
{
- elf_file_t ef = lf->priv;
const Elf_Rel *rellim;
const Elf_Rel *rel;
const Elf_Rela *relalim;
@@ -790,8 +877,8 @@ relocate_file(linker_file_t lf)
rellim = (const Elf_Rel *)((const char *)ef->rel + ef->relsize);
while (rel < rellim) {
symname = symbol_name(ef, rel->r_info);
- if (elf_reloc(lf, rel, ELF_RELOC_REL, symname)) {
- printf("link_elf: symbol %s undefined\n", symname);
+ if (elf_reloc(&ef->lf, rel, ELF_RELOC_REL, symname)) {
+ uprintf("link_elf: symbol %s undefined\n", symname);
return ENOENT;
}
rel++;
@@ -804,8 +891,8 @@ relocate_file(linker_file_t lf)
relalim = (const Elf_Rela *)((const char *)ef->rela + ef->relasize);
while (rela < relalim) {
symname = symbol_name(ef, rela->r_info);
- if (elf_reloc(lf, rela, ELF_RELOC_RELA, symname)) {
- printf("link_elf: symbol %s undefined\n", symname);
+ if (elf_reloc(&ef->lf, rela, ELF_RELOC_RELA, symname)) {
+ uprintf("link_elf: symbol %s undefined\n", symname);
return ENOENT;
}
rela++;
@@ -818,8 +905,8 @@ relocate_file(linker_file_t lf)
rellim = (const Elf_Rel *)((const char *)ef->pltrel + ef->pltrelsize);
while (rel < rellim) {
symname = symbol_name(ef, rel->r_info);
- if (elf_reloc(lf, rel, ELF_RELOC_REL, symname)) {
- printf("link_elf: symbol %s undefined\n", symname);
+ if (elf_reloc(&ef->lf, rel, ELF_RELOC_REL, symname)) {
+ uprintf("link_elf: symbol %s undefined\n", symname);
return ENOENT;
}
rel++;
@@ -832,8 +919,8 @@ relocate_file(linker_file_t lf)
relalim = (const Elf_Rela *)((const char *)ef->pltrela + ef->pltrelasize);
while (rela < relalim) {
symname = symbol_name(ef, rela->r_info);
- if (elf_reloc(lf, rela, ELF_RELOC_RELA, symname)) {
- printf("link_elf: symbol %s undefined\n", symname);
+ if (elf_reloc(&ef->lf, rela, ELF_RELOC_RELA, symname)) {
+ uprintf("link_elf: symbol %s undefined\n", symname);
return ENOENT;
}
rela++;
@@ -866,7 +953,7 @@ elf_hash(const char *name)
int
link_elf_lookup_symbol(linker_file_t lf, const char* name, c_linker_sym_t* sym)
{
- elf_file_t ef = lf->priv;
+ elf_file_t ef = (elf_file_t) lf;
unsigned long symnum;
const Elf_Sym* symp;
const char *strp;
@@ -928,7 +1015,7 @@ link_elf_lookup_symbol(linker_file_t lf, const char* name, c_linker_sym_t* sym)
static int
link_elf_symbol_values(linker_file_t lf, c_linker_sym_t sym, linker_symval_t* symval)
{
- elf_file_t ef = lf->priv;
+ elf_file_t ef = (elf_file_t) lf;
const Elf_Sym* es = (const Elf_Sym*) sym;
if (es >= ef->symtab && ((es - ef->symtab) < ef->nchains)) {
@@ -952,7 +1039,7 @@ static int
link_elf_search_symbol(linker_file_t lf, caddr_t value,
c_linker_sym_t* sym, long* diffp)
{
- elf_file_t ef = lf->priv;
+ elf_file_t ef = (elf_file_t) lf;
u_long off = (uintptr_t) (void *) value;
u_long diff = off;
u_long st_value;
diff --git a/sys/kern/link_elf_obj.c b/sys/kern/link_elf_obj.c
index daf3b30..27d39de 100644
--- a/sys/kern/link_elf_obj.c
+++ b/sys/kern/link_elf_obj.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1998 Doug Rabson
+ * Copyright (c) 1998-2000 Doug Rabson
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -26,6 +26,8 @@
* $FreeBSD$
*/
+#include "opt_ddb.h"
+
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/systm.h>
@@ -48,41 +50,18 @@
#endif
#include <vm/pmap.h>
#include <vm/vm_map.h>
+#include <link.h>
-static int link_elf_load_module(const char*, linker_file_t*);
-static int link_elf_load_file(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*);
-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 struct linker_class_ops link_elf_class_ops = {
- link_elf_load_module,
-};
-
-static struct linker_file_ops link_elf_file_ops = {
- link_elf_lookup_symbol,
- link_elf_symbol_values,
- link_elf_search_symbol,
- link_elf_unload_file,
-};
+#include "linker_if.h"
-static struct linker_file_ops link_elf_module_ops = {
- link_elf_lookup_symbol,
- link_elf_symbol_values,
- link_elf_search_symbol,
- link_elf_unload_module,
-};
typedef struct elf_file {
+ struct linker_file lf; /* Common fields */
+ int preloaded; /* Was file pre-loaded */
caddr_t address; /* Relocation address */
#ifdef SPARSE_MAPPING
vm_object_t object; /* VM object to hold file pages */
#endif
- const Elf_Dyn* dynamic; /* Symbol table etc. */
+ Elf_Dyn* dynamic; /* Symbol table etc. */
Elf_Off nbuckets; /* DT_HASH info */
Elf_Off nchains;
const Elf_Off* buckets;
@@ -107,12 +86,64 @@ typedef struct elf_file {
long ddbstrcnt; /* number of bytes in string table */
caddr_t symbase; /* malloc'ed symbold base */
caddr_t strbase; /* malloc'ed string base */
+#ifdef DDB
+ struct link_map gdb; /* hooks for gdb */
+#endif
} *elf_file_t;
-static int parse_dynamic(linker_file_t lf);
-static int load_dependancies(linker_file_t lf);
-static int relocate_file(linker_file_t lf);
-static int parse_module_symbols(linker_file_t lf);
+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_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*);
+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 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),
+ { 0, 0 }
+};
+
+static struct linker_class link_elf_class = {
+#if ELF_TARG_CLASS == ELFCLASS32
+ "elf32",
+#else
+ "elf64",
+#endif
+ link_elf_methods, sizeof(struct elf_file)
+};
+
+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);
+
+#ifdef DDB
+
+/*
+ * A list of loaded modules for GDB to use for loading symbols.
+ */
+struct r_debug r_debug;
+
+#define GDB_STATE(s) r_debug.r_state = s; r_debug_state();
+
+/*
+ * Function for the debugger to set a breakpoint on to gain control.
+ */
+void
+r_debug_state(void)
+{
+}
+
+#endif
/*
* The kernel symbol table starts here.
@@ -129,35 +160,29 @@ link_elf_init(void* arg)
char *modname;
#endif
-#if ELF_TARG_CLASS == ELFCLASS32
- linker_add_class("elf32", NULL, &link_elf_class_ops);
-#else
- linker_add_class("elf64", NULL, &link_elf_class_ops);
-#endif
+ linker_add_class(&link_elf_class);
#ifdef __ELF__
dp = (Elf_Dyn*) &_DYNAMIC;
if (dp) {
- ef = malloc(sizeof(struct elf_file), M_LINKER, M_NOWAIT);
- if (ef == NULL)
- panic("link_elf_init: Can't create linker structures for kernel");
- bzero(ef, sizeof(*ef));
-
- ef->address = 0;
-#ifdef SPARSE_MAPPING
- ef->object = 0;
-#endif
- ef->dynamic = dp;
modname = NULL;
modptr = preload_search_by_type("elf kernel");
if (modptr)
modname = (char *)preload_search_info(modptr, MODINFO_NAME);
if (modname == NULL)
modname = "kernel";
- linker_kernel_file = linker_make_file(modname, ef, &link_elf_file_ops);
+ linker_kernel_file = linker_make_file(modname, &link_elf_class);
if (linker_kernel_file == NULL)
panic("link_elf_init: Can't create linker structures for kernel");
- parse_dynamic(linker_kernel_file);
+
+ ef = (elf_file_t) linker_kernel_file;
+ ef->address = 0;
+#ifdef SPARSE_MAPPING
+ ef->object = 0;
+#endif
+ ef->dynamic = dp;
+
+ parse_dynamic(ef);
linker_kernel_file->address = (caddr_t) KERNBASE;
linker_kernel_file->size = -(intptr_t)linker_kernel_file->address;
@@ -170,9 +195,24 @@ link_elf_init(void* arg)
if (sizeptr)
linker_kernel_file->size = *(size_t *)sizeptr;
}
- (void)parse_module_symbols(linker_kernel_file);
+ (void)parse_module_symbols(ef);
linker_current_file = linker_kernel_file;
linker_kernel_file->flags |= LINKER_FILE_LINKED;
+
+#ifdef DDB
+ ef->gdb.l_addr = linker_kernel_file->address;
+ ef->gdb.l_name = modname;
+ ef->gdb.l_ld = dp;
+ ef->gdb.l_prev = 0;
+ ef->gdb.l_next = 0;
+
+ r_debug.r_map = &ef->gdb;
+ r_debug.r_brk = r_debug_state;
+ r_debug.r_state = RT_CONSISTENT;
+
+ r_debug_state(); /* say hello to gdb! */
+#endif
+
}
#endif
}
@@ -180,9 +220,8 @@ link_elf_init(void* arg)
SYSINIT(link_elf, SI_SUB_KLD, SI_ORDER_SECOND, link_elf_init, 0);
static int
-parse_module_symbols(linker_file_t lf)
+parse_module_symbols(elf_file_t ef)
{
- elf_file_t ef = lf->priv;
caddr_t pointer;
caddr_t ssym, esym, base;
caddr_t strtab;
@@ -232,10 +271,9 @@ parse_module_symbols(linker_file_t lf)
}
static int
-parse_dynamic(linker_file_t lf)
+parse_dynamic(elf_file_t ef)
{
- elf_file_t ef = lf->priv;
- const Elf_Dyn *dp;
+ Elf_Dyn *dp;
int plttype = DT_REL;
for (dp = ef->dynamic; dp->d_tag != DT_NULL; dp++) {
@@ -298,6 +336,11 @@ parse_dynamic(linker_file_t lf)
if (plttype != DT_REL && plttype != DT_RELA)
return ENOEXEC;
break;
+#ifdef DDB
+ case DT_DEBUG:
+ dp->d_un.d_ptr = (Elf_Addr) &r_debug;
+ break;
+#endif
}
}
@@ -322,8 +365,43 @@ link_elf_error(const char *s)
printf("kldload: %s\n", s);
}
+#ifdef DDB
+
+static void
+link_elf_add_gdb(struct link_map *l)
+{
+ struct link_map *prev;
+
+ /*
+ * Scan to the end of the list.
+ */
+ for (prev = r_debug.r_map; prev->l_next != NULL; prev = prev->l_next)
+ ;
+
+ /* Link in the new entry. */
+ l->l_prev = prev;
+ l->l_next = prev->l_next;
+ prev->l_next = l;
+}
+
+static void
+link_elf_delete_gdb(struct link_map *l)
+{
+ if (l->l_prev == NULL) {
+ if ((r_debug.r_map = l->l_next) != NULL)
+ l->l_next->l_prev = NULL;
+ return;
+ }
+
+ if ((l->l_prev->l_next = l->l_next) != NULL)
+ l->l_next->l_prev = l->l_prev;
+}
+
+#endif /* DDB */
+
static int
-link_elf_load_module(const char *filename, linker_file_t *result)
+link_elf_load_module(linker_class_t cls,
+ const char *filename, linker_file_t *result)
{
caddr_t modptr, baseptr, sizeptr, dynptr;
char *type;
@@ -347,10 +425,13 @@ link_elf_load_module(const char *filename, linker_file_t *result)
if (baseptr == NULL || sizeptr == NULL || dynptr == NULL)
return (EINVAL);
- ef = malloc(sizeof(struct elf_file), M_LINKER, M_WAITOK);
- if (ef == NULL)
- return (ENOMEM);
- bzero(ef, sizeof(*ef));
+ lf = linker_make_file(filename, &link_elf_class);
+ if (lf == NULL) {
+ return ENOMEM;
+ }
+
+ ef = (elf_file_t) lf;
+ ef->preloaded = 1;
ef->modptr = modptr;
ef->address = *(caddr_t *)baseptr;
#ifdef SPARSE_MAPPING
@@ -358,31 +439,37 @@ link_elf_load_module(const char *filename, linker_file_t *result)
#endif
dp = (vm_offset_t)ef->address + *(vm_offset_t *)dynptr;
ef->dynamic = (Elf_Dyn *)dp;
- lf = linker_make_file(filename, ef, &link_elf_module_ops);
- if (lf == NULL) {
- free(ef, M_LINKER);
- return ENOMEM;
- }
+
lf->address = ef->address;
lf->size = *(size_t *)sizeptr;
- error = parse_dynamic(lf);
+ error = parse_dynamic(ef);
if (error) {
linker_file_unload(lf);
return error;
}
- error = load_dependancies(lf);
+ error = load_dependancies(ef);
if (error) {
linker_file_unload(lf);
return error;
}
- error = relocate_file(lf);
+ error = relocate_file(ef);
if (error) {
linker_file_unload(lf);
return error;
}
- (void)parse_module_symbols(lf);
+ (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);
}
@@ -534,8 +621,13 @@ link_elf_load_file(const char* filename, linker_file_t* result)
base_vlimit = round_page(segs[1]->p_vaddr + segs[1]->p_memsz);
mapsize = base_vlimit - base_vaddr;
- ef = malloc(sizeof(struct elf_file), M_LINKER, M_WAITOK);
- bzero(ef, sizeof(*ef));
+ lf = linker_make_file(filename, &link_elf_class);
+ if (!lf) {
+ error = ENOMEM;
+ goto out;
+ }
+
+ ef = (elf_file_t) lf;
#ifdef SPARSE_MAPPING
ef->object = vm_object_allocate(OBJT_DEFAULT, mapsize >> PAGE_SHIFT);
if (ef->object == NULL) {
@@ -551,11 +643,15 @@ link_elf_load_file(const char* filename, linker_file_t* result)
VM_PROT_ALL, VM_PROT_ALL, 0);
if (error) {
vm_object_deallocate(ef->object);
- free(ef, M_LINKER);
+ ef->object = 0;
goto out;
}
#else
ef->address = malloc(mapsize, M_LINKER, M_WAITOK);
+ if (!ef->address) {
+ error = ENOMEM;
+ goto out;
+ }
#endif
mapbase = ef->address;
@@ -568,15 +664,6 @@ link_elf_load_file(const char* filename, linker_file_t* result)
segbase, segs[i]->p_filesz, segs[i]->p_offset,
UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, p);
if (error) {
-#ifdef SPARSE_MAPPING
- vm_map_remove(kernel_map, (vm_offset_t) ef->address,
- (vm_offset_t) ef->address
- + (ef->object->size << PAGE_SHIFT));
- vm_object_deallocate(ef->object);
-#else
- free(ef->address, M_LINKER);
-#endif
- free(ef, M_LINKER);
goto out;
}
bzero(segbase + segs[i]->p_filesz,
@@ -593,32 +680,18 @@ link_elf_load_file(const char* filename, linker_file_t* result)
#endif
}
- ef->dynamic = (const Elf_Dyn *) (mapbase + phdyn->p_vaddr - base_vaddr);
+ ef->dynamic = (Elf_Dyn *) (mapbase + phdyn->p_vaddr - base_vaddr);
- lf = linker_make_file(filename, ef, &link_elf_file_ops);
- if (lf == NULL) {
-#ifdef SPARSE_MAPPING
- vm_map_remove(kernel_map, (vm_offset_t) ef->address,
- (vm_offset_t) ef->address
- + (ef->object->size << PAGE_SHIFT));
- vm_object_deallocate(ef->object);
-#else
- free(ef->address, M_LINKER);
-#endif
- free(ef, M_LINKER);
- error = ENOMEM;
- goto out;
- }
lf->address = ef->address;
lf->size = mapsize;
- error = parse_dynamic(lf);
+ error = parse_dynamic(ef);
if (error)
goto out;
- error = load_dependancies(lf);
+ error = load_dependancies(ef);
if (error)
goto out;
- error = relocate_file(lf);
+ error = relocate_file(ef);
if (error)
goto out;
@@ -675,6 +748,15 @@ link_elf_load_file(const char* filename, linker_file_t* result)
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_ld = ef->dynamic;
+ link_elf_add_gdb(&ef->gdb);
+ GDB_STATE(RT_CONSISTENT);
+#endif
+
nosyms:
*result = lf;
@@ -695,43 +777,49 @@ out:
static void
link_elf_unload_file(linker_file_t file)
{
- elf_file_t ef = file->priv;
+ elf_file_t ef = (elf_file_t) file;
+
+#ifdef DDB
+ if (ef->gdb.l_ld) {
+ 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) {
+ if (ef->preloaded) {
+ link_elf_unload_module(file);
+ return;
+ }
#ifdef SPARSE_MAPPING
- if (ef->object) {
- vm_map_remove(kernel_map, (vm_offset_t) ef->address,
- (vm_offset_t) ef->address
- + (ef->object->size << PAGE_SHIFT));
- vm_object_deallocate(ef->object);
- }
+ if (ef->object) {
+ vm_map_remove(kernel_map, (vm_offset_t) ef->address,
+ (vm_offset_t) ef->address
+ + (ef->object->size << PAGE_SHIFT));
+ vm_object_deallocate(ef->object);
+ }
#else
- if (ef->address)
- free(ef->address, M_LINKER);
+ if (ef->address)
+ free(ef->address, M_LINKER);
#endif
- if (ef->symbase)
- free(ef->symbase, M_LINKER);
- if (ef->strbase)
- free(ef->strbase, M_LINKER);
- free(ef, M_LINKER);
- }
+ if (ef->symbase)
+ free(ef->symbase, M_LINKER);
+ if (ef->strbase)
+ free(ef->strbase, M_LINKER);
}
static void
link_elf_unload_module(linker_file_t file)
{
- elf_file_t ef = file->priv;
-
- if (ef)
- free(ef, M_LINKER);
if (file->filename)
preload_delete_name(file->filename);
}
static int
-load_dependancies(linker_file_t lf)
+load_dependancies(elf_file_t ef)
{
- elf_file_t ef = lf->priv;
linker_file_t lfdep;
char* name;
const Elf_Dyn *dp;
@@ -742,7 +830,7 @@ load_dependancies(linker_file_t lf)
*/
if (linker_kernel_file) {
linker_kernel_file->refs++;
- linker_file_add_dependancy(lf, linker_kernel_file);
+ linker_file_add_dependancy(&ef->lf, linker_kernel_file);
}
for (dp = ef->dynamic; dp->d_tag != DT_NULL; dp++) {
@@ -752,7 +840,7 @@ load_dependancies(linker_file_t lf)
error = linker_load_file(name, &lfdep);
if (error)
goto out;
- error = linker_file_add_dependancy(lf, lfdep);
+ error = linker_file_add_dependancy(&ef->lf, lfdep);
if (error)
goto out;
}
@@ -775,9 +863,8 @@ symbol_name(elf_file_t ef, Elf_Word r_info)
}
static int
-relocate_file(linker_file_t lf)
+relocate_file(elf_file_t ef)
{
- elf_file_t ef = lf->priv;
const Elf_Rel *rellim;
const Elf_Rel *rel;
const Elf_Rela *relalim;
@@ -790,8 +877,8 @@ relocate_file(linker_file_t lf)
rellim = (const Elf_Rel *)((const char *)ef->rel + ef->relsize);
while (rel < rellim) {
symname = symbol_name(ef, rel->r_info);
- if (elf_reloc(lf, rel, ELF_RELOC_REL, symname)) {
- printf("link_elf: symbol %s undefined\n", symname);
+ if (elf_reloc(&ef->lf, rel, ELF_RELOC_REL, symname)) {
+ uprintf("link_elf: symbol %s undefined\n", symname);
return ENOENT;
}
rel++;
@@ -804,8 +891,8 @@ relocate_file(linker_file_t lf)
relalim = (const Elf_Rela *)((const char *)ef->rela + ef->relasize);
while (rela < relalim) {
symname = symbol_name(ef, rela->r_info);
- if (elf_reloc(lf, rela, ELF_RELOC_RELA, symname)) {
- printf("link_elf: symbol %s undefined\n", symname);
+ if (elf_reloc(&ef->lf, rela, ELF_RELOC_RELA, symname)) {
+ uprintf("link_elf: symbol %s undefined\n", symname);
return ENOENT;
}
rela++;
@@ -818,8 +905,8 @@ relocate_file(linker_file_t lf)
rellim = (const Elf_Rel *)((const char *)ef->pltrel + ef->pltrelsize);
while (rel < rellim) {
symname = symbol_name(ef, rel->r_info);
- if (elf_reloc(lf, rel, ELF_RELOC_REL, symname)) {
- printf("link_elf: symbol %s undefined\n", symname);
+ if (elf_reloc(&ef->lf, rel, ELF_RELOC_REL, symname)) {
+ uprintf("link_elf: symbol %s undefined\n", symname);
return ENOENT;
}
rel++;
@@ -832,8 +919,8 @@ relocate_file(linker_file_t lf)
relalim = (const Elf_Rela *)((const char *)ef->pltrela + ef->pltrelasize);
while (rela < relalim) {
symname = symbol_name(ef, rela->r_info);
- if (elf_reloc(lf, rela, ELF_RELOC_RELA, symname)) {
- printf("link_elf: symbol %s undefined\n", symname);
+ if (elf_reloc(&ef->lf, rela, ELF_RELOC_RELA, symname)) {
+ uprintf("link_elf: symbol %s undefined\n", symname);
return ENOENT;
}
rela++;
@@ -866,7 +953,7 @@ elf_hash(const char *name)
int
link_elf_lookup_symbol(linker_file_t lf, const char* name, c_linker_sym_t* sym)
{
- elf_file_t ef = lf->priv;
+ elf_file_t ef = (elf_file_t) lf;
unsigned long symnum;
const Elf_Sym* symp;
const char *strp;
@@ -928,7 +1015,7 @@ link_elf_lookup_symbol(linker_file_t lf, const char* name, c_linker_sym_t* sym)
static int
link_elf_symbol_values(linker_file_t lf, c_linker_sym_t sym, linker_symval_t* symval)
{
- elf_file_t ef = lf->priv;
+ elf_file_t ef = (elf_file_t) lf;
const Elf_Sym* es = (const Elf_Sym*) sym;
if (es >= ef->symtab && ((es - ef->symtab) < ef->nchains)) {
@@ -952,7 +1039,7 @@ static int
link_elf_search_symbol(linker_file_t lf, caddr_t value,
c_linker_sym_t* sym, long* diffp)
{
- elf_file_t ef = lf->priv;
+ elf_file_t ef = (elf_file_t) lf;
u_long off = (uintptr_t) (void *) value;
u_long diff = off;
u_long st_value;
diff --git a/sys/kern/linker_if.m b/sys/kern/linker_if.m
new file mode 100644
index 0000000..e354d12
--- /dev/null
+++ b/sys/kern/linker_if.m
@@ -0,0 +1,75 @@
+#
+# Copyright (c) 2000 Doug Rabson
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $FreeBSD$
+#
+
+#include <sys/linker.h>
+
+INTERFACE linker;
+
+#
+# Lookup a symbol in the file's symbol table. If the symbol is not
+# found then return ENOENT, otherwise zero.
+#
+METHOD int lookup_symbol {
+ linker_file_t file;
+ const char* name;
+ c_linker_sym_t* symp;
+};
+
+METHOD int symbol_values {
+ linker_file_t file;
+ c_linker_sym_t sym;
+ linker_symval_t* valp;
+};
+
+METHOD int search_symbol {
+ linker_file_t file;
+ caddr_t value;
+ c_linker_sym_t* symp;
+ long* diffp;
+};
+
+#
+# Unload a file, releasing dependancies and freeing storage.
+#
+METHOD void unload {
+ linker_file_t file;
+};
+
+#
+# Load a file, returning the new linker_file_t in *result. If
+# the class does not recognise the file type, zero should be
+# returned, without modifying *result. If the file is
+# recognised, the file should be loaded, *result set to the new
+# file and zero returned. If some other error is detected an
+# appropriate errno should be returned.
+#
+STATICMETHOD int load_file {
+ linker_class_t cls;
+ const char* filename;
+ linker_file_t* result;
+};
diff --git a/sys/sys/linker.h b/sys/sys/linker.h
index 8a1446f..5ca1c6c 100644
--- a/sys/sys/linker.h
+++ b/sys/sys/linker.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 1997 Doug Rabson
+ * Copyright (c) 1997-2000 Doug Rabson
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,6 +32,7 @@
#ifdef _KERNEL
#include <machine/elf.h>
+#include <sys/kobj.h>
#ifdef MALLOC_DECLARE
MALLOC_DECLARE(M_LINKER);
@@ -55,29 +56,6 @@ typedef struct linker_symval {
size_t size;
} linker_symval_t;
-struct linker_file_ops {
- /*
- * Lookup a symbol in the file's symbol table. If the symbol is
- * not found then return ENOENT, otherwise zero. If the symbol
- * found is a common symbol, return with *address set to zero and
- * *size set to the size of the common space required. Otherwise
- * set *address the value of the symbol.
- */
- int (*lookup_symbol)(linker_file_t, const char* name,
- c_linker_sym_t* sym);
-
- int (*symbol_values)(linker_file_t, c_linker_sym_t,
- linker_symval_t*);
-
- int (*search_symbol)(linker_file_t, caddr_t value,
- c_linker_sym_t* sym, long* diffp);
-
- /*
- * Unload a file, releasing dependancies and freeing storage.
- */
- void (*unload)(linker_file_t);
-};
-
struct common_symbol {
STAILQ_ENTRY(common_symbol) link;
char* name;
@@ -85,6 +63,7 @@ struct common_symbol {
};
struct linker_file {
+ KOBJ_FIELDS;
int refs; /* reference count */
int userrefs; /* kldload(2) count */
int flags;
@@ -98,9 +77,6 @@ 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 */
- void* priv; /* implementation data */
-
- struct linker_file_ops* ops;
};
/*
@@ -109,24 +85,9 @@ struct linker_file {
typedef struct linker_class *linker_class_t;
typedef TAILQ_HEAD(, linker_class) linker_class_list_t;
-struct linker_class_ops {
- /*
- * Load a file, returning the new linker_file_t in *result. If
- * the class does not recognise the file type, zero should be
- * returned, without modifying *result. If the file is
- * recognised, the file should be loaded, *result set to the new
- * file and zero returned. If some other error is detected an
- * appropriate errno should be returned.
- */
- int (*load_file)(const char* filename, linker_file_t* result);
-};
-
struct linker_class {
+ KOBJ_CLASS_FIELDS;
TAILQ_ENTRY(linker_class) link; /* list of all file classes */
- const char* desc; /* description (e.g. "a.out") */
- void* priv; /* implementation data */
-
- struct linker_class_ops *ops;
};
/*
@@ -143,8 +104,7 @@ extern linker_file_t linker_kernel_file;
/*
* Add a new file class to the linker.
*/
-int linker_add_class(const char* desc, void* priv,
- struct linker_class_ops* ops);
+int linker_add_class(linker_class_t cls);
/*
* Load a file, trying each file class until one succeeds.
@@ -164,8 +124,7 @@ linker_file_t linker_find_file_by_id(int fileid);
/*
* Called from a class handler when a file is laoded.
*/
-linker_file_t linker_make_file(const char* filename, void* priv,
- struct linker_file_ops* ops);
+linker_file_t linker_make_file(const char* filename, linker_class_t cls);
/*
* Unload a file, freeing up memory.
@@ -234,6 +193,10 @@ extern caddr_t preload_search_info(caddr_t mod, int inf);
extern void preload_delete_name(const char *name);
extern void preload_bootstrap_relocate(vm_offset_t offset);
+#ifdef DDB
+extern void r_debug_state(void);
+#endif
+
#ifdef KLD_DEBUG
extern int kld_debug;
OpenPOWER on IntegriCloud