* Rewrite to use kobj(9) instead of hard-coded function tables.
* Report link errors to stdout with uprintf() so that the user can see what went wrong (PR kern/9214). * Add support code to allow module symbols to be loaded into GDB using the debugger's "sharedlibrary" command.
This commit is contained in:
parent
4aa6bac092
commit
326e27d81f
@ -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)
|
||||
{
|
||||
|
@ -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_file_ops link_aout_module_ops = {
|
||||
link_aout_lookup_symbol,
|
||||
link_aout_symbol_values,
|
||||
link_aout_search_symbol,
|
||||
link_aout_unload_module,
|
||||
static struct linker_class link_aout_class = {
|
||||
"a.out", link_aout_methods, sizeof(struct aout_file)
|
||||
};
|
||||
|
||||
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;
|
||||
|
@ -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);
|
||||
#include "linker_if.h"
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
if (ef) {
|
||||
#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);
|
||||
}
|
||||
#else
|
||||
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);
|
||||
#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->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);
|
||||
}
|
||||
#else
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
|
@ -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);
|
||||
#include "linker_if.h"
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
if (ef) {
|
||||
#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);
|
||||
}
|
||||
#else
|
||||
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);
|
||||
#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->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);
|
||||
}
|
||||
#else
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
|
75
sys/kern/linker_if.m
Normal file
75
sys/kern/linker_if.m
Normal file
@ -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;
|
||||
};
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user