From 326e27d81f29a67ad3042ead71d76c0e9541d98f Mon Sep 17 00:00:00 2001 From: Doug Rabson Date: Mon, 24 Apr 2000 17:08:04 +0000 Subject: [PATCH] * 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. --- sys/kern/kern_linker.c | 80 ++++----- sys/kern/link_aout.c | 146 ++++++++-------- sys/kern/link_elf.c | 365 +++++++++++++++++++++++++--------------- sys/kern/link_elf_obj.c | 365 +++++++++++++++++++++++++--------------- sys/kern/linker_if.m | 75 +++++++++ sys/sys/linker.h | 57 ++----- 6 files changed, 639 insertions(+), 449 deletions(-) create mode 100644 sys/kern/linker_if.m diff --git a/sys/kern/kern_linker.c b/sys/kern/kern_linker.c index 13a2491c4b9d..a3193e5efe92 100644 --- a/sys/kern/kern_linker.c +++ b/sys/kern/kern_linker.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1997 Doug Rabson + * Copyright (c) 1997-2000 Doug Rabson * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -46,6 +46,8 @@ #include +#include "linker_if.h" + #ifdef KLD_DEBUG int kld_debug = 0; #endif @@ -59,6 +61,16 @@ static linker_class_list_t classes; static linker_file_list_t linker_files; static int next_file_id = 1; +static char * +linker_strdup(const char *str) +{ + char *result; + + if ((result = malloc((strlen(str) + 1), M_LINKER, M_WAITOK)) != NULL) + strcpy(result, str); + return(result); +} + static void linker_init(void* arg) { @@ -70,21 +82,10 @@ linker_init(void* arg) SYSINIT(linker, SI_SUB_KLD, SI_ORDER_FIRST, linker_init, 0); int -linker_add_class(const char* desc, void* priv, - struct linker_class_ops* ops) +linker_add_class(linker_class_t lc) { - linker_class_t lc; - - lc = malloc(sizeof(struct linker_class), M_LINKER, M_NOWAIT); - if (!lc) - return ENOMEM; - bzero(lc, sizeof(*lc)); - - lc->desc = desc; - lc->priv = priv; - lc->ops = ops; + kobj_class_compile((kobj_class_t) lc); TAILQ_INSERT_HEAD(&classes, lc, link); - return 0; } @@ -267,9 +268,9 @@ linker_load_file(const char* filename, linker_file_t* result) KLD_DPF(FILE, ("linker_load_file: trying to load %s as %s\n", filename, lc->desc)); - error = lc->ops->load_file(koname, &lf); /* First with .ko */ + error = LINKER_LOAD_FILE(lc, koname, &lf); /* First with .ko */ if (lf == NULL && error == ENOENT) - error = lc->ops->load_file(filename, &lf); /* Then try without */ + error = LINKER_LOAD_FILE(lc, filename, &lf); /* Then try without */ /* * If we got something other than ENOENT, then it exists but we cannot * load it for some other reason. @@ -341,10 +342,9 @@ linker_find_file_by_id(int fileid) } linker_file_t -linker_make_file(const char* pathname, void* priv, struct linker_file_ops* ops) +linker_make_file(const char* pathname, linker_class_t lc) { linker_file_t lf = 0; - int namelen; const char *filename; filename = rindex(pathname, '/'); @@ -355,25 +355,20 @@ linker_make_file(const char* pathname, void* priv, struct linker_file_ops* ops) KLD_DPF(FILE, ("linker_make_file: new file, filename=%s\n", filename)); lockmgr(&lock, LK_EXCLUSIVE, 0, curproc); - namelen = strlen(filename) + 1; - lf = malloc(sizeof(struct linker_file) + namelen, M_LINKER, M_WAITOK); + lf = (linker_file_t) kobj_create((kobj_class_t) lc, M_LINKER, M_WAITOK); if (!lf) goto out; - bzero(lf, sizeof(*lf)); lf->refs = 1; lf->userrefs = 0; lf->flags = 0; - lf->filename = (char*) (lf + 1); - strcpy(lf->filename, filename); + lf->filename = linker_strdup(filename); lf->id = next_file_id++; lf->ndeps = 0; lf->deps = NULL; STAILQ_INIT(&lf->common); TAILQ_INIT(&lf->modules); - lf->priv = priv; - lf->ops = ops; TAILQ_INSERT_TAIL(&linker_files, lf, link); out: @@ -438,8 +433,9 @@ linker_file_unload(linker_file_t file) free(cp, M_LINKER); } - file->ops->unload(file); - free(file, M_LINKER); + LINKER_UNLOAD(file); + free(file->filename, M_LINKER); + kobj_delete((kobj_t) file, M_LINKER); out: return error; @@ -480,8 +476,8 @@ linker_file_lookup_symbol(linker_file_t file, const char* name, int deps) KLD_DPF(SYM, ("linker_file_lookup_symbol: file=%x, name=%s, deps=%d\n", file, name, deps)); - if (file->ops->lookup_symbol(file, name, &sym) == 0) { - file->ops->symbol_values(file, sym, &symval); + if (LINKER_LOOKUP_SYMBOL(file, name, &sym) == 0) { + LINKER_SYMBOL_VALUES(file, sym, &symval); if (symval.value == 0) /* * For commons, first look them up in the dependancies and @@ -581,7 +577,7 @@ linker_ddb_lookup(const char *symstr, c_linker_sym_t *sym) linker_file_t lf; for (lf = TAILQ_FIRST(&linker_files); lf; lf = TAILQ_NEXT(lf, link)) { - if (lf->ops->lookup_symbol(lf, symstr, sym) == 0) + if (LINKER_LOOKUP_SYMBOL(lf, symstr, sym) == 0) return 0; } return ENOENT; @@ -599,7 +595,7 @@ linker_ddb_search_symbol(caddr_t value, c_linker_sym_t *sym, long *diffp) best = 0; bestdiff = off; for (lf = TAILQ_FIRST(&linker_files); lf; lf = TAILQ_NEXT(lf, link)) { - if (lf->ops->search_symbol(lf, value, &es, &diff) != 0) + if (LINKER_SEARCH_SYMBOL(lf, value, &es, &diff) != 0) continue; if (es != 0 && diff < bestdiff) { best = es; @@ -625,7 +621,7 @@ linker_ddb_symbol_values(c_linker_sym_t sym, linker_symval_t *symval) linker_file_t lf; for (lf = TAILQ_FIRST(&linker_files); lf; lf = TAILQ_NEXT(lf, link)) { - if (lf->ops->symbol_values(lf, sym, symval) == 0) + if (LINKER_SYMBOL_VALUES(lf, sym, symval) == 0) return 0; } return ENOENT; @@ -857,8 +853,8 @@ kldsym(struct proc *p, struct kldsym_args *uap) error = ENOENT; goto out; } - if (lf->ops->lookup_symbol(lf, symstr, &sym) == 0 && - lf->ops->symbol_values(lf, sym, &symval) == 0) { + if (LINKER_LOOKUP_SYMBOL(lf, symstr, &sym) == 0 && + LINKER_SYMBOL_VALUES(lf, sym, &symval) == 0) { lookup.symvalue = (uintptr_t)symval.value; lookup.symsize = symval.size; error = copyout(&lookup, SCARG(uap, data), sizeof(lookup)); @@ -866,8 +862,8 @@ kldsym(struct proc *p, struct kldsym_args *uap) error = ENOENT; } else { for (lf = TAILQ_FIRST(&linker_files); lf; lf = TAILQ_NEXT(lf, link)) { - if (lf->ops->lookup_symbol(lf, symstr, &sym) == 0 && - lf->ops->symbol_values(lf, sym, &symval) == 0) { + if (LINKER_LOOKUP_SYMBOL(lf, symstr, &sym) == 0 && + LINKER_SYMBOL_VALUES(lf, sym, &symval) == 0) { lookup.symvalue = (uintptr_t)symval.value; lookup.symsize = symval.size; error = copyout(&lookup, SCARG(uap, data), sizeof(lookup)); @@ -920,7 +916,7 @@ linker_preload(void* arg) } lf = NULL; for (lc = TAILQ_FIRST(&classes); lc; lc = TAILQ_NEXT(lc, link)) { - error = lc->ops->load_file(modname, &lf); + error = LINKER_LOAD_FILE(lc, modname, &lf); if (error) { lf = NULL; break; @@ -975,16 +971,6 @@ static char linker_path[MAXPATHLEN] = "/;/boot/;/modules/"; SYSCTL_STRING(_kern, OID_AUTO, module_path, CTLFLAG_RW, linker_path, sizeof(linker_path), "module load search path"); -static char * -linker_strdup(const char *str) -{ - char *result; - - if ((result = malloc((strlen(str) + 1), M_LINKER, M_WAITOK)) != NULL) - strcpy(result, str); - return(result); -} - char * linker_search_path(const char *name) { diff --git a/sys/kern/link_aout.c b/sys/kern/link_aout.c index de5518de13fa..f9b55e5fcb17 100644 --- a/sys/kern/link_aout.c +++ b/sys/kern/link_aout.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1997 Doug Rabson + * Copyright (c) 1997-2000 Doug Rabson * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -42,6 +42,8 @@ #include +#include "linker_if.h" + #ifndef __ELF__ #include #include @@ -51,7 +53,15 @@ #include #include -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; diff --git a/sys/kern/link_elf.c b/sys/kern/link_elf.c index daf3b3072702..27d39ded6c41 100644 --- a/sys/kern/link_elf.c +++ b/sys/kern/link_elf.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1998 Doug Rabson + * Copyright (c) 1998-2000 Doug Rabson * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -26,6 +26,8 @@ * $FreeBSD$ */ +#include "opt_ddb.h" + #include #include #include @@ -48,41 +50,18 @@ #endif #include #include +#include -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; diff --git a/sys/kern/link_elf_obj.c b/sys/kern/link_elf_obj.c index daf3b3072702..27d39ded6c41 100644 --- a/sys/kern/link_elf_obj.c +++ b/sys/kern/link_elf_obj.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1998 Doug Rabson + * Copyright (c) 1998-2000 Doug Rabson * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -26,6 +26,8 @@ * $FreeBSD$ */ +#include "opt_ddb.h" + #include #include #include @@ -48,41 +50,18 @@ #endif #include #include +#include -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; diff --git a/sys/kern/linker_if.m b/sys/kern/linker_if.m new file mode 100644 index 000000000000..e354d1266af6 --- /dev/null +++ b/sys/kern/linker_if.m @@ -0,0 +1,75 @@ +# +# Copyright (c) 2000 Doug Rabson +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# $FreeBSD$ +# + +#include + +INTERFACE linker; + +# +# Lookup a symbol in the file's symbol table. If the symbol is not +# found then return ENOENT, otherwise zero. +# +METHOD int lookup_symbol { + linker_file_t file; + const char* name; + c_linker_sym_t* symp; +}; + +METHOD int symbol_values { + linker_file_t file; + c_linker_sym_t sym; + linker_symval_t* valp; +}; + +METHOD int search_symbol { + linker_file_t file; + caddr_t value; + c_linker_sym_t* symp; + long* diffp; +}; + +# +# Unload a file, releasing dependancies and freeing storage. +# +METHOD void unload { + linker_file_t file; +}; + +# +# Load a file, returning the new linker_file_t in *result. If +# the class does not recognise the file type, zero should be +# returned, without modifying *result. If the file is +# recognised, the file should be loaded, *result set to the new +# file and zero returned. If some other error is detected an +# appropriate errno should be returned. +# +STATICMETHOD int load_file { + linker_class_t cls; + const char* filename; + linker_file_t* result; +}; diff --git a/sys/sys/linker.h b/sys/sys/linker.h index 8a1446f922da..5ca1c6cd71f0 100644 --- a/sys/sys/linker.h +++ b/sys/sys/linker.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 1997 Doug Rabson + * Copyright (c) 1997-2000 Doug Rabson * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -32,6 +32,7 @@ #ifdef _KERNEL #include +#include #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;