* 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:
Doug Rabson 2000-04-24 17:08:04 +00:00
parent 4aa6bac092
commit 326e27d81f
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=59603
6 changed files with 639 additions and 449 deletions

View File

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

View File

@ -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 @@ link_aout_load_file(const char* filename, linker_file_t* result)
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;

View File

@ -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 @@ link_elf_load_file(const char* filename, linker_file_t* result)
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;

View File

@ -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 @@ link_elf_load_file(const char* filename, linker_file_t* result)
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
View 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;
};

View File

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