diff options
| -rw-r--r-- | libexec/rtld-elf/alpha/reloc.c | 3 | ||||
| -rw-r--r-- | libexec/rtld-elf/debug.h | 4 | ||||
| -rw-r--r-- | libexec/rtld-elf/map_object.c | 63 | ||||
| -rw-r--r-- | libexec/rtld-elf/rtld.c | 340 | ||||
| -rw-r--r-- | libexec/rtld-elf/rtld.h | 27 |
5 files changed, 328 insertions, 109 deletions
diff --git a/libexec/rtld-elf/alpha/reloc.c b/libexec/rtld-elf/alpha/reloc.c index 03d8c171183d..1b55d06e767c 100644 --- a/libexec/rtld-elf/alpha/reloc.c +++ b/libexec/rtld-elf/alpha/reloc.c @@ -60,8 +60,7 @@ extern Elf_Dyn _DYNAMIC; /* Relocate a non-PLT object with addend. */ static int -reloc_non_plt_obj(Obj_Entry *obj_rtld, const Obj_Entry *obj, - const Elf_Rela *rela) +reloc_non_plt_obj(Obj_Entry *obj_rtld, Obj_Entry *obj, const Elf_Rela *rela) { Elf_Addr *where = (Elf_Addr *) (obj->relocbase + rela->r_offset); diff --git a/libexec/rtld-elf/debug.h b/libexec/rtld-elf/debug.h index 8d57ec7930ab..b3563386eaff 100644 --- a/libexec/rtld-elf/debug.h +++ b/libexec/rtld-elf/debug.h @@ -36,7 +36,9 @@ #error "This file must be compiled with GCC" #endif -extern void debug_printf(const char *, ...); +#include <sys/cdefs.h> + +extern void debug_printf(const char *, ...) __printflike(1, 2); extern int debug; #ifdef DEBUG diff --git a/libexec/rtld-elf/map_object.c b/libexec/rtld-elf/map_object.c index 0d4114fc6c25..d7b6978ae9ee 100644 --- a/libexec/rtld-elf/map_object.c +++ b/libexec/rtld-elf/map_object.c @@ -27,9 +27,11 @@ #include <sys/param.h> #include <sys/mman.h> +#include <sys/stat.h> #include <errno.h> #include <stddef.h> +#include <stdlib.h> #include <string.h> #include <unistd.h> @@ -46,7 +48,7 @@ static int protflags(int); /* Elf flags -> mmap protection */ * for the shared object. Returns NULL on failure. */ Obj_Entry * -map_object(int fd, const char *path) +map_object(int fd, const char *path, const struct stat *sb) { Obj_Entry *obj; union { @@ -60,6 +62,7 @@ map_object(int fd, const char *path) int nsegs; Elf_Phdr *phdyn; Elf_Phdr *phphdr; + Elf_Phdr *phinterp; caddr_t mapbase; size_t mapsize; Elf_Off base_offset; @@ -134,11 +137,14 @@ map_object(int fd, const char *path) phdr = (Elf_Phdr *) (u.buf + u.hdr.e_phoff); phlimit = phdr + u.hdr.e_phnum; nsegs = 0; - phdyn = NULL; - phphdr = NULL; + phdyn = phphdr = phinterp = NULL; while (phdr < phlimit) { switch (phdr->p_type) { + case PT_INTERP: + phinterp = phdr; + break; + case PT_LOAD: if (nsegs >= 2) { _rtld_error("%s: too many PT_LOAD segments", path); @@ -226,23 +232,62 @@ map_object(int fd, const char *path) } } - obj = CNEW(Obj_Entry); + obj = obj_new(); + if (sb != NULL) { + obj->dev = sb->st_dev; + obj->ino = sb->st_ino; + } obj->mapbase = mapbase; obj->mapsize = mapsize; obj->textsize = round_page(segs[0]->p_vaddr + segs[0]->p_memsz) - base_vaddr; obj->vaddrbase = base_vaddr; obj->relocbase = mapbase - base_vaddr; - obj->dynamic = (const Elf_Dyn *) - (mapbase + (phdyn->p_vaddr - base_vaddr)); + obj->dynamic = (const Elf_Dyn *) (obj->relocbase + phdyn->p_vaddr); if (u.hdr.e_entry != 0) - obj->entry = (caddr_t) (mapbase + (u.hdr.e_entry - base_vaddr)); + obj->entry = (caddr_t) (obj->relocbase + u.hdr.e_entry); if (phphdr != NULL) { - obj->phdr = (const Elf_Phdr *) - (mapbase + (phphdr->p_vaddr - base_vaddr)); + obj->phdr = (const Elf_Phdr *) (obj->relocbase + phphdr->p_vaddr); obj->phsize = phphdr->p_memsz; } + if (phinterp != NULL) + obj->interp = (const char *) (obj->relocbase + phinterp->p_vaddr); + + return obj; +} +void +obj_free(Obj_Entry *obj) +{ + Objlist_Entry *elm; + + free(obj->path); + while (obj->needed != NULL) { + Needed_Entry *needed = obj->needed; + obj->needed = needed->next; + free(needed); + } + while (!STAILQ_EMPTY(&obj->dldags)) { + elm = STAILQ_FIRST(&obj->dldags); + STAILQ_REMOVE_HEAD(&obj->dldags, link); + free(elm); + } + while (!STAILQ_EMPTY(&obj->dagmembers)) { + elm = STAILQ_FIRST(&obj->dagmembers); + STAILQ_REMOVE_HEAD(&obj->dagmembers, link); + free(elm); + } + free(obj); +} + +Obj_Entry * +obj_new(void) +{ + Obj_Entry *obj; + + obj = CNEW(Obj_Entry); + STAILQ_INIT(&obj->dldags); + STAILQ_INIT(&obj->dagmembers); return obj; } diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c index a4a71bc537ef..8ba21b4f26c7 100644 --- a/libexec/rtld-elf/rtld.c +++ b/libexec/rtld-elf/rtld.c @@ -37,6 +37,7 @@ #include <sys/param.h> #include <sys/mman.h> +#include <sys/stat.h> #include <dlfcn.h> #include <err.h> @@ -61,6 +62,7 @@ #define trace() msg("trace: " __XSTRING(__LINE__) "\n"); #define END_SYM "_end" +#define PATH_RTLD "/usr/libexec/ld-elf.so.1" /* Types. */ typedef void (*func_ptr_type)(); @@ -77,6 +79,8 @@ static Obj_Entry *digest_phdr(const Elf_Phdr *, int, caddr_t, const char *); static Obj_Entry *dlcheck(void *); static char *find_library(const char *, const Obj_Entry *); static const char *gethints(void); +static void init_dag(Obj_Entry *); +static void init_dag1(Obj_Entry *root, Obj_Entry *obj); static void init_rtld(caddr_t); static bool is_exported(const Elf_Sym *); static void linkmap_add(Obj_Entry *); @@ -85,13 +89,18 @@ static int load_needed_objects(Obj_Entry *); static int load_preload_objects(void); static Obj_Entry *load_object(char *); static Obj_Entry *obj_from_addr(const void *); +static void objlist_add(Objlist *, Obj_Entry *); +static Objlist_Entry *objlist_find(Objlist *, const Obj_Entry *); +static void objlist_remove(Objlist *, Obj_Entry *); static int relocate_objects(Obj_Entry *, bool); static void rtld_exit(void); static char *search_library_path(const char *, const char *); static void set_program_var(const char *, const void *); +static const Elf_Sym *symlook_list(const char *, unsigned long, + Objlist *, const Obj_Entry **, bool in_plt); static void trace_loaded_objects(Obj_Entry *obj); static void unload_object(Obj_Entry *, bool do_fini_funcs); -static void unref_object_dag(Obj_Entry *); +static void unref_dag(Obj_Entry *); void r_debug_state(void); void xprintf(const char *, ...); @@ -108,12 +117,16 @@ static char *ld_library_path; /* Environment variable for search path */ static char *ld_preload; /* Environment variable for libraries to load first */ static char *ld_tracing; /* Called from ldd to print libs */ -static Obj_Entry **main_tail; /* Value of obj_tail after loading main and - its needed shared libraries */ static Obj_Entry *obj_list; /* Head of linked list of shared objects */ static Obj_Entry **obj_tail; /* Link field of last object in list */ static Obj_Entry *obj_main; /* The main program shared object */ static Obj_Entry obj_rtld; /* The dynamic linker shared object */ +static unsigned long curmark; /* Current mark value */ + +static Objlist list_global = /* Objects dlopened with RTLD_GLOBAL */ + STAILQ_HEAD_INITIALIZER(list_global); +static Objlist list_main = /* Objects loaded at program startup */ + STAILQ_HEAD_INITIALIZER(list_main); static Elf_Sym sym_zero; /* For resolving undefined weak refs. */ @@ -171,6 +184,7 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp) Elf_Auxinfo *aux; Elf_Auxinfo *auxp; const char *argv0; + Obj_Entry *obj; /* * On entry, the dynamic linker itself has not been relocated yet. @@ -228,7 +242,7 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp) if (aux_info[AT_EXECFD] != NULL) { /* Load the main program. */ int fd = aux_info[AT_EXECFD]->a_un.a_val; dbg("loading main program"); - obj_main = map_object(fd, argv0); + obj_main = map_object(fd, argv0, NULL); close(fd); if (obj_main == NULL) die(); @@ -252,6 +266,19 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp) obj_main->path = xstrdup(argv0); obj_main->mainprog = true; + + /* + * Get the actual dynamic linker pathname from the executable if + * possible. (It should always be possible.) That ensures that + * gdb will find the right dynamic linker even if a non-standard + * one is being used. + */ + if (obj_main->interp != NULL && + strcmp(obj_main->interp, obj_rtld.path) != 0) { + free(obj_rtld.path); + obj_rtld.path = xstrdup(obj_main->interp); + } + digest_dynamic(obj_main); linkmap_add(obj_main); @@ -273,7 +300,9 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp) dbg("loading needed objects"); if (load_needed_objects(obj_main) == -1) die(); - main_tail = obj_tail; + + for (obj = obj_list; obj != NULL; obj = obj->next) + objlist_add(&list_main, obj); if (ld_tracing) { /* We're done */ trace_loaded_objects(obj_main); @@ -307,7 +336,7 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp) } Elf_Addr -_rtld_bind(const Obj_Entry *obj, Elf_Word reloff) +_rtld_bind(Obj_Entry *obj, Elf_Word reloff) { const Elf_Rel *rel; const Elf_Sym *def; @@ -548,11 +577,12 @@ digest_dynamic(Obj_Entry *obj) static Obj_Entry * digest_phdr(const Elf_Phdr *phdr, int phnum, caddr_t entry, const char *path) { - Obj_Entry *obj = CNEW(Obj_Entry); + Obj_Entry *obj; const Elf_Phdr *phlimit = phdr + phnum; const Elf_Phdr *ph; int nsegs = 0; + obj = obj_new(); for (ph = phdr; ph < phlimit; ph++) { switch (ph->p_type) { @@ -565,6 +595,10 @@ digest_phdr(const Elf_Phdr *phdr, int phnum, caddr_t entry, const char *path) obj->phsize = ph->p_memsz; break; + case PT_INTERP: + obj->interp = (const char *) ph->p_vaddr; + break; + case PT_LOAD: if (nsegs >= 2) { _rtld_error("%s: too many PT_LOAD segments", path); @@ -681,95 +715,94 @@ find_library(const char *name, const Obj_Entry *refobj) * defining object via the reference parameter DEFOBJ_OUT. */ const Elf_Sym * -find_symdef(unsigned long symnum, const Obj_Entry *refobj, +find_symdef(unsigned long symnum, Obj_Entry *refobj, const Obj_Entry **defobj_out, bool in_plt) { const Elf_Sym *ref; - const Elf_Sym *strongdef; - const Elf_Sym *weakdef; + const Elf_Sym *def; + const Elf_Sym *symp; const Obj_Entry *obj; - const Obj_Entry *strongobj; - const Obj_Entry *weakobj; + const Obj_Entry *defobj; + const Objlist_Entry *elm; const char *name; unsigned long hash; ref = refobj->symtab + symnum; name = refobj->strtab + ref->st_name; hash = elf_hash(name); + def = NULL; + defobj = NULL; + curmark++; if (refobj->symbolic) { /* Look first in the referencing object */ - const Elf_Sym *def = symlook_obj(name, hash, refobj, in_plt); - if (def != NULL) { - *defobj_out = refobj; - return def; + symp = symlook_obj(name, hash, refobj, in_plt); + refobj->mark = curmark; + if (symp != NULL) { + def = symp; + defobj = refobj; } } - /* - * Look in all loaded objects. Skip the referencing object, if - * we have already searched it. We keep track of the first weak - * definition and the first strong definition we encounter. If - * we find a strong definition we stop searching, because there - * won't be anything better than that. - */ - strongdef = weakdef = NULL; - strongobj = weakobj = NULL; - for (obj = obj_list; obj != NULL; obj = obj->next) { - if (obj != refobj || !refobj->symbolic) { - const Elf_Sym *def = symlook_obj(name, hash, obj, in_plt); - if (def != NULL) { - if (ELF_ST_BIND(def->st_info) == STB_WEAK) { - if (weakdef == NULL) { - weakdef = def; - weakobj = obj; - } - } else { - strongdef = def; - strongobj = obj; - break; /* We are done. */ - } - } + /* Search all objects loaded at program start up. */ + if (def == NULL || ELF_ST_BIND(def->st_info) == STB_WEAK) { + symp = symlook_list(name, hash, &list_main, &obj, in_plt); + if (symp != NULL && + (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) { + def = symp; + defobj = obj; } } - /* - * If we still don't have a strong definition, search the dynamic - * linker itself, and possibly resolve the symbol from there. - * This is how the application links to dynamic linker services - * such as dlopen. Only the values listed in the "exports" array - * can be resolved from the dynamic linker. - */ - if (strongdef == NULL) { - const Elf_Sym *def = symlook_obj(name, hash, &obj_rtld, in_plt); - if (def != NULL && is_exported(def)) { - if (ELF_ST_BIND(def->st_info) == STB_WEAK) { - if (weakdef == NULL) { - weakdef = def; - weakobj = &obj_rtld; - } - } else { - strongdef = def; - strongobj = &obj_rtld; - } + /* Search all dlopened DAGs containing the referencing object. */ + STAILQ_FOREACH(elm, &refobj->dldags, link) { + if (def != NULL && ELF_ST_BIND(def->st_info) != STB_WEAK) + break; + symp = symlook_list(name, hash, &elm->obj->dagmembers, &obj, in_plt); + if (symp != NULL && + (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) { + def = symp; + defobj = obj; } } - if (strongdef != NULL) { - *defobj_out = strongobj; - return strongdef; + /* Search all RTLD_GLOBAL objects. */ + if (def == NULL || ELF_ST_BIND(def->st_info) == STB_WEAK) { + symp = symlook_list(name, hash, &list_global, &obj, in_plt); + if (symp != NULL && + (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) { + def = symp; + defobj = obj; + } } - if (weakdef != NULL) { - *defobj_out = weakobj; - return weakdef; + + /* + * Search the dynamic linker itself, and possibly resolve the + * symbol from there. This is how the application links to + * dynamic linker services such as dlopen. Only the values listed + * in the "exports" array can be resolved from the dynamic linker. + */ + if (def == NULL || ELF_ST_BIND(def->st_info) == STB_WEAK) { + symp = symlook_obj(name, hash, &obj_rtld, in_plt); + if (symp != NULL && is_exported(symp)) { + def = symp; + defobj = &obj_rtld; + } } - if (ELF_ST_BIND(ref->st_info) == STB_WEAK) { - *defobj_out = obj_main; - return &sym_zero; + /* + * If we found no definition and the reference is weak, treat the + * symbol as having the value zero. + */ + if (def == NULL && ELF_ST_BIND(ref->st_info) == STB_WEAK) { + def = &sym_zero; + defobj = obj_main; } - _rtld_error("%s: Undefined symbol \"%s\"", refobj->path, name); - return NULL; + if (def != NULL) + *defobj_out = defobj; + else + _rtld_error("%s: Undefined symbol \"%s\"", refobj->path, name); + return def; } /* @@ -811,6 +844,28 @@ gethints(void) return hints[0] != '\0' ? hints : NULL; } +static void +init_dag(Obj_Entry *root) +{ + curmark++; + init_dag1(root, root); +} + +static void +init_dag1(Obj_Entry *root, Obj_Entry *obj) +{ + const Needed_Entry *needed; + + if (obj->mark == curmark) + return; + obj->mark = curmark; + objlist_add(&obj->dldags, root); + objlist_add(&root->dagmembers, obj); + for (needed = obj->needed; needed != NULL; needed = needed->next) + if (needed->obj != NULL) + init_dag1(root, needed->obj); +} + /* * Initialize the dynamic linker. The argument is the address at which * the dynamic linker has been mapped into memory. The primary task of @@ -826,7 +881,7 @@ init_rtld(caddr_t mapbase) * aren't yet initialized sufficiently to do that. Below we will * replace the static version with a dynamically-allocated copy. */ - obj_rtld.path = "/usr/libexec/ld-elf.so.1"; + obj_rtld.path = PATH_RTLD; obj_rtld.rtld = true; obj_rtld.mapbase = mapbase; #ifdef PIC @@ -943,20 +998,42 @@ static Obj_Entry * load_object(char *path) { Obj_Entry *obj; + int fd = -1; + struct stat sb; for (obj = obj_list->next; obj != NULL; obj = obj->next) if (strcmp(obj->path, path) == 0) break; - if (obj == NULL) { /* First use of this object, so we must map it in */ - int fd; - + /* + * If we didn't find a match by pathname, open the file and check + * again by device and inode. This avoids false mismatches caused + * by multiple links or ".." in pathnames. + * + * To avoid a race, we open the file and use fstat() rather than + * using stat(). + */ + if (obj == NULL) { if ((fd = open(path, O_RDONLY)) == -1) { _rtld_error("Cannot open \"%s\"", path); return NULL; } + if (fstat(fd, &sb) == -1) { + _rtld_error("Cannot fstat \"%s\"", path); + close(fd); + return NULL; + } + for (obj = obj_list->next; obj != NULL; obj = obj->next) { + if (obj->ino == sb.st_ino && obj->dev == sb.st_dev) { + close(fd); + break; + } + } + } + + if (obj == NULL) { /* First use of this object, so we must map it in */ dbg("loading \"%s\"", path); - obj = map_object(fd, path); + obj = map_object(fd, path, &sb); close(fd); if (obj == NULL) { free(path); @@ -1001,6 +1078,38 @@ obj_from_addr(const void *addr) return NULL; } +static void +objlist_add(Objlist *list, Obj_Entry *obj) +{ + Objlist_Entry *elm; + + elm = NEW(Objlist_Entry); + elm->obj = obj; + STAILQ_INSERT_TAIL(list, elm, link); +} + +static Objlist_Entry * +objlist_find(Objlist *list, const Obj_Entry *obj) +{ + Objlist_Entry *elm; + + STAILQ_FOREACH(elm, list, link) + if (elm->obj == obj) + return elm; + return NULL; +} + +static void +objlist_remove(Objlist *list, Obj_Entry *obj) +{ + Objlist_Entry *elm; + + if ((elm = objlist_find(list, obj)) != NULL) { + STAILQ_REMOVE(list, elm, Struct_Objlist_Entry, link); + free(elm); + } +} + /* * Relocate newly-loaded shared objects. The argument is a pointer to * the Obj_Entry for the first such object. All objects from the first @@ -1154,11 +1263,14 @@ dlopen(const char *name, int mode) if (obj) { obj->dl_refcount++; + if (mode & RTLD_GLOBAL && objlist_find(&list_global, obj) == NULL) + objlist_add(&list_global, obj); + mode &= RTLD_MODEMASK; if (*old_obj_tail != NULL) { /* We loaded something new. */ assert(*old_obj_tail == obj); if (load_needed_objects(obj) == -1 || - relocate_objects(obj, mode == RTLD_NOW) == -1) { + (init_dag(obj), relocate_objects(obj, mode == RTLD_NOW)) == -1) { unload_object(obj, false); obj->dl_refcount--; obj = NULL; @@ -1178,9 +1290,11 @@ dlsym(void *handle, const char *name) const Obj_Entry *obj; unsigned long hash; const Elf_Sym *def; + const Obj_Entry *defobj; hash = elf_hash(name); def = NULL; + defobj = NULL; if (handle == NULL || handle == RTLD_NEXT) { void *retaddr; @@ -1190,12 +1304,16 @@ dlsym(void *handle, const char *name) _rtld_error("Cannot determine caller's shared object"); return NULL; } - if (handle == NULL) /* Just the caller's shared object. */ + if (handle == NULL) { /* Just the caller's shared object. */ def = symlook_obj(name, hash, obj, true); - else { /* All the shared objects after the caller's */ - while ((obj = obj->next) != NULL) - if ((def = symlook_obj(name, hash, obj, true)) != NULL) + defobj = obj; + } else { /* All the shared objects after the caller's */ + while ((obj = obj->next) != NULL) { + if ((def = symlook_obj(name, hash, obj, true)) != NULL) { + defobj = obj; break; + } + } } } else { if ((obj = dlcheck(handle)) == NULL) @@ -1203,20 +1321,20 @@ dlsym(void *handle, const char *name) if (obj->mainprog) { /* Search main program and all libraries loaded by it. */ - for ( ; obj != *main_tail; obj = obj->next) - if ((def = symlook_obj(name, hash, obj, true)) != NULL) - break; + curmark++; + def = symlook_list(name, hash, &list_main, &defobj, true); } else { /* * XXX - This isn't correct. The search should include the whole * DAG rooted at the given object. */ def = symlook_obj(name, hash, obj, true); + defobj = obj; } } if (def != NULL) - return obj->relocbase + def->st_value; + return defobj->relocbase + def->st_value; _rtld_error("Undefined symbol \"%s\"", name); return NULL; @@ -1359,6 +1477,35 @@ set_program_var(const char *name, const void *value) } } +static const Elf_Sym * +symlook_list(const char *name, unsigned long hash, Objlist *objlist, + const Obj_Entry **defobj_out, bool in_plt) +{ + const Elf_Sym *symp; + const Elf_Sym *def; + const Obj_Entry *defobj; + const Objlist_Entry *elm; + + def = NULL; + defobj = NULL; + STAILQ_FOREACH(elm, objlist, link) { + if (elm->obj->mark == curmark) + continue; + elm->obj->mark = curmark; + if ((symp = symlook_obj(name, hash, elm->obj, in_plt)) != NULL) { + if (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK) { + def = symp; + defobj = elm->obj; + if (ELF_ST_BIND(def->st_info) != STB_WEAK) + break; + } + } + } + if (def != NULL) + *defobj_out = defobj; + return def; +} + /* * Search the symbol table of a single shared object for a symbol of * the given name. Returns a pointer to the symbol, or NULL if no @@ -1484,13 +1631,17 @@ trace_loaded_objects(Obj_Entry *obj) } } +/* + * Note, this is called only for objects loaded by dlopen(). + */ static void unload_object(Obj_Entry *root, bool do_fini_funcs) { - unref_object_dag(root); + unref_dag(root); if (root->refcount == 0) { /* We are finished with some objects. */ Obj_Entry *obj; Obj_Entry **linkp; + Objlist_Entry *elm; /* Finalize objects that are about to be unmapped. */ if (do_fini_funcs) @@ -1498,21 +1649,22 @@ unload_object(Obj_Entry *root, bool do_fini_funcs) if (obj->refcount == 0 && obj->fini != NULL) (*obj->fini)(); + /* Remove the DAG from all objects' DAG lists. */ + STAILQ_FOREACH(elm, &root->dagmembers , link) + objlist_remove(&elm->obj->dldags, root); + + /* Remove the DAG from the RTLD_GLOBAL list. */ + objlist_remove(&list_global, root); + /* Unmap all objects that are no longer referenced. */ linkp = &obj_list->next; while ((obj = *linkp) != NULL) { if (obj->refcount == 0) { dbg("unloading \"%s\"", obj->path); munmap(obj->mapbase, obj->mapsize); - free(obj->path); - while (obj->needed != NULL) { - Needed_Entry *needed = obj->needed; - obj->needed = needed->next; - free(needed); - } linkmap_delete(obj); *linkp = obj->next; - free(obj); + obj_free(obj); } else linkp = &obj->next; } @@ -1521,7 +1673,7 @@ unload_object(Obj_Entry *root, bool do_fini_funcs) } static void -unref_object_dag(Obj_Entry *root) +unref_dag(Obj_Entry *root) { const Needed_Entry *needed; @@ -1530,7 +1682,7 @@ unref_object_dag(Obj_Entry *root) if (root->refcount == 0) for (needed = root->needed; needed != NULL; needed = needed->next) if (needed->obj != NULL) - unref_object_dag(needed->obj); + unref_dag(needed->obj); } /* diff --git a/libexec/rtld-elf/rtld.h b/libexec/rtld-elf/rtld.h index 2fe8b1507d49..c63e7d08836b 100644 --- a/libexec/rtld-elf/rtld.h +++ b/libexec/rtld-elf/rtld.h @@ -29,6 +29,7 @@ #define RTLD_H 1 #include <sys/types.h> +#include <sys/queue.h> #include <link.h> #include <elf.h> @@ -48,8 +49,16 @@ typedef unsigned char bool; #define false 0 #define true 1 +struct stat; struct Struct_Obj_Entry; +typedef struct Struct_Objlist_Entry { + STAILQ_ENTRY(Struct_Objlist_Entry) link; + struct Struct_Obj_Entry *obj; +} Objlist_Entry; + +typedef STAILQ_HEAD(Struct_Objlist, Struct_Objlist_Entry) Objlist; + typedef struct Struct_Needed_Entry { struct Struct_Needed_Entry *next; struct Struct_Obj_Entry *obj; @@ -61,6 +70,10 @@ typedef struct Struct_Needed_Entry { * * Items marked with "(%)" are dynamically allocated, and must be freed * when the structure is destroyed. + * + * CAUTION: It appears that the JDK port peeks into these structures. + * It looks at "next" and "mapbase" at least. Don't add new members + * near the front, until this can be straightened out. */ typedef struct Struct_Obj_Entry { /* @@ -85,6 +98,7 @@ typedef struct Struct_Obj_Entry { caddr_t entry; /* Entry point */ const Elf_Phdr *phdr; /* Program header if it is mapped, else NULL */ size_t phsize; /* Size of program header in bytes */ + const char *interp; /* Pathname of the interpreter, if any */ /* Items from the dynamic section. */ Elf_Addr *pltgot; /* PLT or GOT, depending on architecture */ @@ -118,13 +132,18 @@ typedef struct Struct_Obj_Entry { bool traced; /* Already printed in ldd trace output */ struct link_map linkmap; /* for GDB */ + Objlist dldags; /* Object belongs to these dlopened DAGs (%) */ + Objlist dagmembers; /* DAG has these members (%) */ + dev_t dev; /* Object's filesystem's device */ + ino_t ino; /* Object's inode number */ + unsigned long mark; /* Set to "curmark" to avoid repeat visits */ } Obj_Entry; #define RTLD_MAGIC 0xd550b87a #define RTLD_VERSION 1 extern void _rtld_error(const char *, ...) __printflike(1, 2); -extern Obj_Entry *map_object(int, const char *); +extern Obj_Entry *map_object(int, const char *, const struct stat *); extern void *xcalloc(size_t); extern void *xmalloc(size_t); extern char *xstrdup(const char *); @@ -135,9 +154,11 @@ extern Elf_Addr _GLOBAL_OFFSET_TABLE_[]; */ int do_copy_relocations(Obj_Entry *); unsigned long elf_hash(const char *); -const Elf_Sym *find_symdef(unsigned long, const Obj_Entry *, - const Obj_Entry **, bool); +const Elf_Sym *find_symdef(unsigned long, Obj_Entry *, const Obj_Entry **, + bool); void init_pltgot(Obj_Entry *); +void obj_free(Obj_Entry *); +Obj_Entry *obj_new(void); int reloc_non_plt(Obj_Entry *, Obj_Entry *); int reloc_plt(Obj_Entry *, bool); void _rtld_bind_start(void); |
