typedef void * (*path_enum_proc) (const char *path, size_t len, void *arg);
/*
- * This structure provides a reentrant way to keep a list of objects and
- * check which ones have already been processed in some way.
- */
-typedef struct Struct_DoneList {
- const Obj_Entry **objs; /* Array of object pointers */
- unsigned int num_alloc; /* Allocated size of the array */
- unsigned int num_used; /* Number of array slots used */
-} DoneList;
-
-/*
* Function declarations.
*/
static const char *_getenv_ld(const char *id);
static void digest_dynamic(Obj_Entry *, int);
static Obj_Entry *digest_phdr(const Elf_Phdr *, int, caddr_t, const char *);
static Obj_Entry *dlcheck(void *);
+static Obj_Entry *dlopen_object(const char *name, Obj_Entry *refobj,
+ int lo_flags, int mode);
static Obj_Entry *do_load_object(int, const char *, char *, struct stat *, int);
static int do_search_info(const Obj_Entry *obj, int, struct dl_serinfo *);
static bool donelist_check(DoneList *, const Obj_Entry *);
static bool is_exported(const Elf_Sym *);
static void linkmap_add(Obj_Entry *);
static void linkmap_delete(Obj_Entry *);
+static void load_filtees(Obj_Entry *, int flags, RtldLockState *);
+static void unload_filtees(Obj_Entry *);
static int load_needed_objects(Obj_Entry *, int);
static int load_preload_objects(void);
static Obj_Entry *load_object(const char *, const Obj_Entry *, int);
static void objlist_push_tail(Objlist *, Obj_Entry *);
static void objlist_remove(Objlist *, Obj_Entry *);
static void *path_enumerate(const char *, path_enum_proc, void *);
-static int relocate_objects(Obj_Entry *, bool, Obj_Entry *);
+static int relocate_objects(Obj_Entry *, bool, Obj_Entry *, RtldLockState *);
static int rtld_dirname(const char *, char *);
static int rtld_dirname_abs(const char *, char *);
static void rtld_exit(void);
static char *search_library_path(const char *, const char *);
static const void **get_program_var_addr(const char *);
static void set_program_var(const char *, const void *);
-static const Elf_Sym *symlook_default(const char *, unsigned long,
- const Obj_Entry *, const Obj_Entry **, const Ver_Entry *, int);
-static const Elf_Sym *symlook_list(const char *, unsigned long, const Objlist *,
- const Obj_Entry **, const Ver_Entry *, int, DoneList *);
-static const Elf_Sym *symlook_needed(const char *, unsigned long,
- const Needed_Entry *, const Obj_Entry **, const Ver_Entry *,
- int, DoneList *);
+static int symlook_default(SymLook *, const Obj_Entry *refobj);
+static void symlook_init_from_req(SymLook *, const SymLook *);
+static int symlook_list(SymLook *, const Objlist *, DoneList *);
+static int symlook_needed(SymLook *, const Needed_Entry *, DoneList *);
+static int symlook_obj1(SymLook *, const Obj_Entry *);
static void trace_loaded_objects(Obj_Entry *);
static void unlink_object(Obj_Entry *);
static void unload_object(Obj_Entry *);
static char *error_message; /* Message for dlerror(), or NULL */
struct r_debug r_debug; /* for GDB; */
static bool libmap_disable; /* Disable libmap */
+static bool ld_loadfltr; /* Immediate filters processing */
static char *libmap_override; /* Maps to use in addition to libmap.conf */
static bool trust; /* False for setuid and setgid programs */
static bool dangerous_ld_env; /* True if environment variables have been
const char *callee_obj,
const char *callee_func,
void *stack);
-static Obj_Entry *rtld_functrace_obj; /* Object thereof */
+static const Obj_Entry *rtld_functrace_obj; /* Object thereof */
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 **preload_tail;
/* marino: DO NOT MOVE THESE VARIABLES TO _rtld
Obj_Entry **preload_tail;
Objlist initlist;
- from global to here. It will break the DRAWF2 unwind scheme.
+ from global to here. It will break the DWARF2 unwind scheme.
The system compilers were unaffected, but not gcc 4.6
*/
|| unsetenv("LD_ELF_HINTS_PATH")
|| unsetenv("LD_LIBMAP")
|| unsetenv("LD_LIBMAP_DISABLE")
+ || unsetenv("LD_LOADFLTR")
) {
_rtld_error("environment corrupt; aborting");
die();
}
}
ld_debug = _getenv_ld("LD_DEBUG");
+ libmap_disable = _getenv_ld("LD_LIBMAP_DISABLE") != NULL;
+ libmap_override = (char *)_getenv_ld("LD_LIBMAP");
ld_library_path = _getenv_ld("LD_LIBRARY_PATH");
ld_preload = (char *)_getenv_ld("LD_PRELOAD");
ld_elf_hints_path = _getenv_ld("LD_ELF_HINTS_PATH");
- libmap_override = (char *)_getenv_ld("LD_LIBMAP");
- libmap_disable = _getenv_ld("LD_LIBMAP_DISABLE") != NULL;
+ ld_loadfltr = _getenv_ld("LD_LOADFLTR") != NULL;
dangerous_ld_env = (ld_library_path != NULL)
|| (ld_preload != NULL)
|| (ld_elf_hints_path != NULL)
+ || ld_loadfltr
|| (libmap_override != NULL)
|| libmap_disable
;
*/
if (relocate_objects(obj_main,
- ld_bind_now != NULL && *ld_bind_now != '\0', &obj_rtld) == -1)
+ ld_bind_now != NULL && *ld_bind_now != '\0', &obj_rtld, NULL) == -1)
die();
dbg("doing copy relocations");
_rtld_call_init(void)
{
RtldLockState lockstate;
+ Obj_Entry *obj;
wlock_acquire(rtld_bind_lock, &lockstate);
objlist_call_init(&initlist, &lockstate);
objlist_clear(&initlist);
+ dbg("loading filtees");
+ for (obj = obj_list->next; obj != NULL; obj = obj->next) {
+ if (ld_loadfltr || obj->z_loadfltr)
+ load_filtees(obj, 0, &lockstate);
+ }
lock_release(rtld_bind_lock, &lockstate);
}
Elf_Addr *where;
Elf_Addr target;
RtldLockState lockstate;
- int do_reloc = 1;
rlock_acquire(rtld_bind_lock, &lockstate);
if (sigsetjmp(lockstate.env, 0) != 0)
rel = (const Elf_Rel *) ((caddr_t) obj->pltrela + reloff);
where = (Elf_Addr *) (obj->relocbase + rel->r_offset);
- def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj, true, NULL);
+ def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj, true, NULL,
+ &lockstate);
if (def == NULL)
die();
defobj->path,
defobj->strtab + def->st_name,
stack))
- do_reloc = 0;
+ lock_release(rtld_bind_lock, &lockstate);
+ return target;
}
- if (do_reloc)
- target = reloc_jmpslot(where, target, defobj, obj, rel);
+ /*
+ * Write the new contents for the jmpslot. Note that depending on
+ * architecture, the value which we need to return back to the
+ * lazy binding trampoline may or may not be the target
+ * address. The value returned from reloc_jmpslot() is the value
+ * that the trampoline needs.
+ */
+ target = reloc_jmpslot(where, target, defobj, obj, rel);
lock_release(rtld_bind_lock, &lockstate);
return target;
}
{
const Elf_Dyn *dynp;
Needed_Entry **needed_tail = &obj->needed;
+ Needed_Entry **needed_filtees_tail = &obj->needed_filtees;
+ Needed_Entry **needed_aux_filtees_tail = &obj->needed_aux_filtees;
int plttype = DT_REL;
*dyn_rpath = NULL;
}
break;
+ case DT_FILTER:
+ if (!obj->rtld) {
+ Needed_Entry *nep = NEW(Needed_Entry);
+ nep->name = dynp->d_un.d_val;
+ nep->obj = NULL;
+ nep->next = NULL;
+
+ *needed_filtees_tail = nep;
+ needed_filtees_tail = &nep->next;
+ }
+ break;
+
+ case DT_AUXILIARY:
+ if (!obj->rtld) {
+ Needed_Entry *nep = NEW(Needed_Entry);
+ nep->name = dynp->d_un.d_val;
+ nep->obj = NULL;
+ nep->next = NULL;
+
+ *needed_aux_filtees_tail = nep;
+ needed_aux_filtees_tail = &nep->next;
+ }
+ break;
+
case DT_PLTGOT:
obj->pltgot = (Elf_Addr *) (obj->relocbase + dynp->d_un.d_ptr);
break;
obj->bind_now = true;
if (dynp->d_un.d_val & DF_1_NODELETE)
obj->z_nodelete = true;
+ if (dynp->d_un.d_val & DF_1_LOADFLTR)
+ obj->z_loadfltr = true;
break;
default:
*/
const Elf_Sym *
find_symdef(unsigned long symnum, const Obj_Entry *refobj,
- const Obj_Entry **defobj_out, int flags, SymCache *cache)
+ const Obj_Entry **defobj_out, int flags, SymCache *cache,
+ RtldLockState *lockstate)
{
const Elf_Sym *ref;
const Elf_Sym *def;
const Obj_Entry *defobj;
- const Ver_Entry *ventry;
+ SymLook req;
const char *name;
- unsigned long hash;
+ int res;
/*
* If we have already found this symbol, get the information from
ref = refobj->symtab + symnum;
name = refobj->strtab + ref->st_name;
+ def = NULL;
defobj = NULL;
/*
_rtld_error("%s: Bogus symbol table entry %lu", refobj->path,
symnum);
}
- ventry = fetch_ventry(refobj, symnum);
- hash = elf_hash(name);
- def = symlook_default(name, hash, refobj, &defobj, ventry, flags);
+ symlook_init(&req, name);
+ req.flags = flags;
+ req.ventry = fetch_ventry(refobj, symnum);
+ req.lockstate = lockstate;
+ res = symlook_default(&req, refobj);
+ if (res == 0) {
+ def = req.sym_out;
+ defobj = req.defobj_out;
+ }
} else {
def = ref;
defobj = refobj;
return;
donelist_init(&donelist);
init_dag1(root, root, &donelist);
+ root->dag_inited = true;
}
static void
for (needed = obj->needed; needed != NULL; needed = needed->next)
if (needed->obj != NULL)
init_dag1(root, needed->obj, dlp);
- root->dag_inited = true;
}
/*
* that symbols can be found.
*/
- relocate_objects(&objtmp, true, &objtmp);
+ relocate_objects(&objtmp, true, &objtmp, NULL);
}
/* Initialize the object list. */
return false;
}
+static void
+free_needed_filtees(Needed_Entry *n)
+{
+ Needed_Entry *needed, *needed1;
+
+ for (needed = n; needed != NULL; needed = needed->next) {
+ if (needed->obj != NULL) {
+ dlclose(needed->obj);
+ needed->obj = NULL;
+ }
+ }
+ for (needed = n; needed != NULL; needed = needed1) {
+ needed1 = needed->next;
+ free(needed);
+ }
+}
+
+static void
+unload_filtees(Obj_Entry *obj)
+{
+
+ free_needed_filtees(obj->needed_filtees);
+ obj->needed_filtees = NULL;
+ free_needed_filtees(obj->needed_aux_filtees);
+ obj->needed_aux_filtees = NULL;
+ obj->filtees_loaded = false;
+}
+
+static void
+load_filtee1(Obj_Entry *obj, Needed_Entry *needed, int flags)
+{
+
+ for (; needed != NULL; needed = needed->next) {
+ needed->obj = dlopen_object(obj->strtab + needed->name, obj,
+ flags, ((ld_loadfltr || obj->z_loadfltr) ? RTLD_NOW : RTLD_LAZY) |
+ RTLD_LOCAL);
+ }
+}
+
+static void
+load_filtees(Obj_Entry *obj, int flags, RtldLockState *lockstate)
+{
+
+ lock_restart_for_upgrade(lockstate);
+ if (!obj->filtees_loaded) {
+ load_filtee1(obj, obj->needed_filtees, flags);
+ load_filtee1(obj, obj->needed_aux_filtees, flags);
+ obj->filtees_loaded = true;
+ }
+}
+
+static int
+process_needed(Obj_Entry *obj, Needed_Entry *needed, int flags)
+{
+ Obj_Entry *obj1;
+
+ for (; needed != NULL; needed = needed->next) {
+ obj1 = needed->obj = load_object(obj->strtab + needed->name, obj,
+ flags & ~RTLD_LO_NOLOAD);
+ if (obj1 == NULL && !ld_tracing && (flags & RTLD_LO_FILTEES) == 0)
+ return (-1);
+ if (obj1 != NULL && obj1->z_nodelete && !obj1->ref_nodel) {
+ dbg("obj %s nodelete", obj1->path);
+ init_dag(obj1);
+ ref_dag(obj1);
+ obj1->ref_nodel = true;
+ }
+ }
+ return (0);
+}
+
/*
* Given a shared object, traverse its list of needed objects, and load
* each of them. Returns 0 on success. Generates an error message and
static int
load_needed_objects(Obj_Entry *first, int flags)
{
- Obj_Entry *obj, *obj1;
+ Obj_Entry *obj;
for (obj = first; obj != NULL; obj = obj->next) {
- Needed_Entry *needed;
-
- for (needed = obj->needed; needed != NULL; needed = needed->next) {
- obj1 = needed->obj = load_object(obj->strtab + needed->name, obj,
- flags & ~RTLD_LO_NOLOAD);
- if (obj1 == NULL && !ld_tracing)
- return -1;
- if (obj1 != NULL && obj1->z_nodelete && !obj1->ref_nodel) {
- dbg("obj %s nodelete", obj1->path);
- init_dag(obj1);
- ref_dag(obj1);
- obj1->ref_nodel = true;
- }
- }
+ if (process_needed(obj, obj->needed, flags) == -1)
+ return (-1);
}
return (0);
}
-#define RTLD_FUNCTRACE "_rtld_functrace"
-
static int
load_preload_objects(void)
{
size_t len = strcspn(p, delim);
char savech;
Obj_Entry *obj;
- const Elf_Sym *sym;
+ SymLook req;
+ int res;
savech = p[len];
p[len] = '\0';
p += strspn(p, delim);
/* Check for the magic tracing function */
- sym = symlook_obj(RTLD_FUNCTRACE, elf_hash(RTLD_FUNCTRACE), obj, NULL, 1);
- if (sym != NULL) {
- rtld_functrace = (void *)(obj->relocbase + sym->st_value);
- rtld_functrace_obj = obj;
+ symlook_init(&req, RTLD_FUNCTRACE);
+ res = symlook_obj(&req, obj);
+ if (res == 0) {
+ rtld_functrace = (void *)(req.defobj_out->relocbase +
+ req.sym_out->st_value);
+ rtld_functrace_obj = req.defobj_out;
}
}
LD_UTRACE(UTRACE_PRELOAD_FINISHED, NULL, NULL, 0, 0, NULL);
* or -1 on failure.
*/
static int
-relocate_objects(Obj_Entry *first, bool bind_now, Obj_Entry *rtldobj)
+relocate_objects(Obj_Entry *first, bool bind_now, Obj_Entry *rtldobj,
+ RtldLockState *lockstate)
{
Obj_Entry *obj;
}
/* Process the non-PLT relocations. */
- if (reloc_non_plt(obj, rtldobj))
+ if (reloc_non_plt(obj, rtldobj, lockstate))
return -1;
/*
return -1;
/* Relocate the jump slots if we are doing immediate binding. */
if (obj->bind_now || bind_now)
- if (reloc_jmpslots(obj) == -1)
+ if (reloc_jmpslots(obj, lockstate) == -1)
return -1;
/* Set the special PLT or GOT entries. */
void *
dlopen(const char *name, int mode)
{
- Obj_Entry **old_obj_tail;
- Obj_Entry *obj;
- Objlist initlist;
- RtldLockState lockstate;
- int result, lo_flags;
+ int lo_flags;
LD_UTRACE(UTRACE_DLOPEN_START, NULL, NULL, 0, mode, name);
ld_tracing = (mode & RTLD_TRACE) == 0 ? NULL : "1";
if (ld_tracing != NULL)
lo_flags |= RTLD_LO_TRACE;
+ return (dlopen_object(name, obj_main, lo_flags,
+ mode & (RTLD_MODEMASK | RTLD_GLOBAL)));
+}
+
+static Obj_Entry *
+dlopen_object(const char *name, Obj_Entry *refobj, int lo_flags, int mode)
+{
+ Obj_Entry **old_obj_tail;
+ Obj_Entry *obj;
+ Objlist initlist;
+ RtldLockState lockstate;
+ int result;
+
objlist_init(&initlist);
wlock_acquire(rtld_bind_lock, &lockstate);
obj = obj_main;
obj->refcount++;
} else {
- obj = load_object(name, obj_main, lo_flags);
+ obj = load_object(name, refobj, lo_flags);
}
if (obj) {
obj->dl_refcount++;
if (mode & RTLD_GLOBAL && objlist_find(&list_global, obj) == NULL)
objlist_push_tail(&list_global, obj);
- mode &= RTLD_MODEMASK;
if (*old_obj_tail != NULL) { /* We loaded something new. */
assert(*old_obj_tail == obj);
- result = load_needed_objects(obj, RTLD_LO_DLOPEN);
+ result = load_needed_objects(obj, lo_flags & RTLD_LO_DLOPEN);
init_dag(obj);
ref_dag(obj);
if (result != -1)
result = rtld_verify_versions(&obj->dagmembers);
if (result != -1 && ld_tracing)
goto trace;
- if (result == -1 ||
- (relocate_objects(obj, mode == RTLD_NOW, &obj_rtld)) == -1) {
+ if (result == -1 || (relocate_objects(obj, (mode & RTLD_MODEMASK)
+ == RTLD_NOW, &obj_rtld, &lockstate)) == -1) {
obj->dl_refcount--;
unref_dag(obj);
if (obj->refcount == 0)
{
DoneList donelist;
const Obj_Entry *obj, *defobj;
- const Elf_Sym *def, *symp;
- unsigned long hash;
+ const Elf_Sym *def;
+ SymLook req;
RtldLockState lockstate;
+ int res;
- hash = elf_hash(name);
def = NULL;
defobj = NULL;
- flags |= SYMLOOK_IN_PLT;
+ symlook_init(&req, name);
+ req.ventry = ve;
+ req.flags = flags | SYMLOOK_IN_PLT;
+ req.lockstate = &lockstate;
rlock_acquire(rtld_bind_lock, &lockstate);
if (sigsetjmp(lockstate.env, 0) != 0)
return NULL;
}
if (handle == NULL) { /* Just the caller's shared object. */
- def = symlook_obj(name, hash, obj, ve, flags);
- defobj = obj;
+ res = symlook_obj(&req, obj);
+ if (res == 0) {
+ def = req.sym_out;
+ defobj = req.defobj_out;
+ }
} else if (handle == RTLD_NEXT || /* Objects after caller's */
handle == RTLD_SELF) { /* ... caller included */
if (handle == RTLD_NEXT)
obj = obj->next;
for (; obj != NULL; obj = obj->next) {
- if ((symp = symlook_obj(name, hash, obj, ve, flags)) != NULL) {
- if (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK) {
- def = symp;
- defobj = obj;
+ res = symlook_obj(&req, obj);
+ if (res == 0) {
+ if (def == NULL ||
+ ELF_ST_BIND(req.sym_out->st_info) != STB_WEAK) {
+ def = req.sym_out;
+ defobj = req.defobj_out;
if (ELF_ST_BIND(def->st_info) != STB_WEAK)
break;
}
* dynamic linker services such as dlopen.
*/
if (def == NULL || ELF_ST_BIND(def->st_info) == STB_WEAK) {
- symp = symlook_obj(name, hash, &obj_rtld, ve, flags);
- if (symp != NULL) {
- def = symp;
- defobj = &obj_rtld;
+ res = symlook_obj(&req, &obj_rtld);
+ if (res == 0 && is_exported(req.sym_out)) {
+ def = req.sym_out;
+ defobj = req.defobj_out;
}
}
} else {
assert(handle == RTLD_DEFAULT);
- def = symlook_default(name, hash, obj, &defobj, ve, flags);
+ res = symlook_default(&req, obj);
+ if (res == 0) {
+ defobj = req.defobj_out;
+ def = req.sym_out;
+ }
}
} else {
if ((obj = dlcheck(handle)) == NULL) {
donelist_init(&donelist);
if (obj->mainprog) {
/* Search main program and all libraries loaded by it. */
- def = symlook_list(name, hash, &list_main, &defobj, ve, flags,
- &donelist);
-
+ res = symlook_list(&req, &list_main, &donelist);
+ if (res == 0) {
+ def = req.sym_out;
+ defobj = req.defobj_out;
+ } else {
/*
- * We do not distinguish between 'main' object and global scope.
- * If symbol is not defined by objects loaded at startup, continue
- * search among dynamically loaded objects with RTLD_GLOBAL
- * scope.
+ * We do not distinguish between 'main' object and
+ * global scope. If symbol is not defined by objects
+ * loaded at startup, continue search among
+ * dynamically loaded objects with RTLD_GLOBAL scope.
*/
- if (def == NULL)
- def = symlook_list(name, hash, &list_global, &defobj, ve,
- flags, &donelist);
+ res = symlook_list(&req, &list_global, &donelist);
+ if (res == 0) {
+ def = req.sym_out;
+ defobj = req.defobj_out;
+ }
+ }
} else {
Needed_Entry fake;
fake.next = NULL;
fake.obj = (Obj_Entry *)obj;
fake.name = 0;
- def = symlook_needed(name, hash, &fake, &defobj, ve, flags,
- &donelist);
+ res = symlook_needed(&req, &fake, &donelist);
+ if (res == 0) {
+ def = req.sym_out;
+ defobj = req.defobj_out;
+ }
}
}
get_program_var_addr(const char *name)
{
const Obj_Entry *obj;
- unsigned long hash;
+ SymLook req;
- hash = elf_hash(name);
+ symlook_init(&req, name);
for (obj = obj_main; obj != NULL; obj = obj->next) {
- const Elf_Sym *def;
-
- if ((def = symlook_obj(name, hash, obj, NULL, 0)) != NULL) {
- const void **addr;
-
- addr = (const void **)(obj->relocbase + def->st_value);
- return addr;
+ if (symlook_obj(&req, obj) == 0) {
+ return ((const void **)(req.defobj_out->relocbase +
+ req.sym_out->st_value));
}
}
return (NULL);
* no definition was found. Returns a pointer to the Obj_Entry of the
* defining object via the reference parameter DEFOBJ_OUT.
*/
-static const Elf_Sym *
-symlook_default(const char *name, unsigned long hash, const Obj_Entry *refobj,
- const Obj_Entry **defobj_out, const Ver_Entry *ventry, int flags)
+static int
+symlook_default(SymLook *req, const Obj_Entry *refobj)
{
DoneList donelist;
const Elf_Sym *def;
- const Elf_Sym *symp;
- const Obj_Entry *obj;
const Obj_Entry *defobj;
const Objlist_Entry *elm;
+ SymLook req1;
+ int res;
def = NULL;
defobj = NULL;
donelist_init(&donelist);
+ symlook_init_from_req(&req1, req);
/* Look first in the referencing object if linked symbolically. */
if (refobj->symbolic && !donelist_check(&donelist, refobj)) {
- symp = symlook_obj(name, hash, refobj, ventry, flags);
- if (symp != NULL) {
- def = symp;
- defobj = refobj;
+ res = symlook_obj(&req1, refobj);
+ if (res == 0) {
+ def = req1.sym_out;
+ defobj = req1.defobj_out;
+ assert(defobj != NULL);
}
}
/* 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, ventry, flags,
- &donelist);
- if (symp != NULL &&
- (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) {
- def = symp;
- defobj = obj;
+ res = symlook_list(&req1, &list_main, &donelist);
+ if (res == 0 &&
+ (def == NULL || ELF_ST_BIND(req1.sym_out->st_info) != STB_WEAK)) {
+ def = req1.sym_out;
+ defobj = req1.defobj_out;
+ assert(defobj != NULL);
}
}
STAILQ_FOREACH(elm, &list_global, link) {
if (def != NULL && ELF_ST_BIND(def->st_info) != STB_WEAK)
break;
- symp = symlook_list(name, hash, &elm->obj->dagmembers, &obj, ventry,
- flags, &donelist);
- if (symp != NULL &&
- (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) {
- def = symp;
- defobj = obj;
+ res = symlook_list(&req1, &elm->obj->dagmembers, &donelist);
+ if (res == 0 &&
+ (def == NULL || ELF_ST_BIND(req1.sym_out->st_info) != STB_WEAK)) {
+ def = req1.sym_out;
+ defobj = req1.defobj_out;
+ assert(defobj != NULL);
}
}
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, ventry,
- flags, &donelist);
- if (symp != NULL &&
- (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK)) {
- def = symp;
- defobj = obj;
+ res = symlook_list(&req1, &elm->obj->dagmembers, &donelist);
+ if (res == 0 &&
+ (def == NULL || ELF_ST_BIND(req1.sym_out->st_info) != STB_WEAK)) {
+ def = req1.sym_out;
+ defobj = req1.defobj_out;
+ assert(defobj != NULL);
}
}
* 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, ventry, flags);
- if (symp != NULL && is_exported(symp)) {
- def = symp;
- defobj = &obj_rtld;
+ res = symlook_obj(&req1, &obj_rtld);
+ if (res == 0 && is_exported(req1.sym_out)) {
+ def = req1.sym_out;
+ defobj = req1.defobj_out;
+ assert(defobj != NULL);
}
}
- if (def != NULL)
- *defobj_out = defobj;
- return def;
+ if (def != NULL) {
+ assert(defobj != NULL);
+ req->defobj_out = defobj;
+ req->sym_out = def;
+ return (0);
+ }
+ return (ESRCH);
}
-static const Elf_Sym *
-symlook_list(const char *name, unsigned long hash, const Objlist *objlist,
- const Obj_Entry **defobj_out, const Ver_Entry *ventry, int flags,
- DoneList *dlp)
+static int
+symlook_list(SymLook *req, const Objlist *objlist, DoneList *dlp)
{
- const Elf_Sym *symp;
const Elf_Sym *def;
const Obj_Entry *defobj;
const Objlist_Entry *elm;
+ SymLook req1;
+ int res;
def = NULL;
defobj = NULL;
STAILQ_FOREACH(elm, objlist, link) {
if (donelist_check(dlp, elm->obj))
continue;
- if ((symp = symlook_obj(name, hash, elm->obj, ventry, flags)) != NULL) {
- if (def == NULL || ELF_ST_BIND(symp->st_info) != STB_WEAK) {
- def = symp;
- defobj = elm->obj;
+ symlook_init_from_req(&req1, req);
+ if ((res = symlook_obj(&req1, elm->obj)) == 0) {
+ if (def == NULL || ELF_ST_BIND(req1.sym_out->st_info) != STB_WEAK) {
+ def = req1.sym_out;
+ defobj = req1.defobj_out;
if (ELF_ST_BIND(def->st_info) != STB_WEAK)
break;
}
}
}
- if (def != NULL)
- *defobj_out = defobj;
- return def;
+ if (def != NULL) {
+ req->sym_out = def;
+ req->defobj_out = defobj;
+ return (0);
+ }
+ return (ESRCH);
}
/*
* breadth-first. Returns a pointer to the symbol, or NULL if no
* definition was found.
*/
-static const Elf_Sym *
-symlook_needed(const char *name, unsigned long hash, const Needed_Entry *needed,
- const Obj_Entry **defobj_out, const Ver_Entry *ventry, int flags,
- DoneList *dlp)
+static int
+symlook_needed(SymLook *req, const Needed_Entry *needed, DoneList *dlp)
{
const Elf_Sym *def, *def_w;
const Needed_Entry *n;
- const Obj_Entry *obj, *defobj, *defobj1;
+ const Obj_Entry *defobj, *defobj1;
+ SymLook req1;
+ int res;
def = def_w = NULL;
defobj = NULL;
+ symlook_init_from_req(&req1, req);
for (n = needed; n != NULL; n = n->next) {
- if ((obj = n->obj) == NULL ||
- donelist_check(dlp, obj) ||
- (def = symlook_obj(name, hash, obj, ventry, flags)) == NULL)
+ if (n->obj == NULL || donelist_check(dlp, n->obj) ||
+ (res = symlook_obj(&req1, n->obj)) != 0)
continue;
- defobj = obj;
+ def = req1.sym_out;
+ defobj = req1.defobj_out;
if (ELF_ST_BIND(def->st_info) != STB_WEAK) {
- *defobj_out = defobj;
- return (def);
+ req->defobj_out = defobj;
+ req->sym_out = def;
+ return (0);
}
}
/*
* directly needed objects, or found symbol is weak.
*/
for (n = needed; n != NULL; n = n->next) {
- if ((obj = n->obj) == NULL)
+ if (n->obj == NULL)
continue;
- def_w = symlook_needed(name, hash, obj->needed, &defobj1,
- ventry, flags, dlp);
- if (def_w == NULL)
+ res = symlook_needed(&req1, n->obj->needed, dlp);
+ if (res != 0)
continue;
+ def_w = req1.sym_out;
+ defobj1 = req1.defobj_out;
if (def == NULL || ELF_ST_BIND(def_w->st_info) != STB_WEAK) {
def = def_w;
defobj = defobj1;
if (ELF_ST_BIND(def_w->st_info) != STB_WEAK)
break;
}
- if (def != NULL)
- *defobj_out = defobj;
- return (def);
+ if (def != NULL) {
+ req->sym_out = def;
+ req->defobj_out = defobj;
+ return (0);
+ }
+ return (ESRCH);
}
/*
* Search the symbol table of a single shared object for a symbol of
* the given name and version, if requested. Returns a pointer to the
- * symbol, or NULL if no definition was found.
+ * symbol, or NULL if no definition was found. If the object is
+ * filter, return filtered symbol from filtee.
*
* The symbol's hash value is passed in for efficiency reasons; that
* eliminates many recomputations of the hash value.
*/
-const Elf_Sym *
-symlook_obj(const char *name, unsigned long hash, const Obj_Entry *obj,
- const Ver_Entry *ventry, int flags)
+int
+symlook_obj(SymLook *req, const Obj_Entry *obj)
+{
+ DoneList donelist;
+ SymLook req1;
+ int res, mres;
+
+ mres = symlook_obj1(req, obj);
+ if (mres == 0) {
+ if (obj->needed_filtees != NULL) {
+ load_filtees(__DECONST(Obj_Entry *, obj), 0, req->lockstate);
+ donelist_init(&donelist);
+ symlook_init_from_req(&req1, req);
+ res = symlook_needed(&req1, obj->needed_filtees, &donelist);
+ if (res == 0) {
+ req->sym_out = req1.sym_out;
+ req->defobj_out = req1.defobj_out;
+ }
+ return (res);
+ }
+ if (obj->needed_aux_filtees != NULL) {
+ load_filtees(__DECONST(Obj_Entry *, obj), 0, req->lockstate);
+ donelist_init(&donelist);
+ symlook_init_from_req(&req1, req);
+ res = symlook_needed(&req1, obj->needed_aux_filtees, &donelist);
+ if (res == 0) {
+ req->sym_out = req1.sym_out;
+ req->defobj_out = req1.defobj_out;
+ return (res);
+ }
+ }
+ }
+ return (mres);
+}
+
+static int
+symlook_obj1(SymLook *req, const Obj_Entry *obj)
{
unsigned long symnum;
const Elf_Sym *vsymp;
int vcount;
if (obj->buckets == NULL)
- return NULL;
+ return (ESRCH);
vsymp = NULL;
vcount = 0;
- symnum = obj->buckets[hash % obj->nbuckets];
+ symnum = obj->buckets[req->hash % obj->nbuckets];
for (; symnum != STN_UNDEF; symnum = obj->chains[symnum]) {
const Elf_Sym *symp;
const char *strp;
if (symnum >= obj->nchains)
- return NULL; /* Bad object */
+ return (ESRCH); /* Bad object */
symp = obj->symtab + symnum;
strp = obj->strtab + symp->st_name;
case STT_TLS:
if (symp->st_shndx != SHN_UNDEF)
break;
- else if (((flags & SYMLOOK_IN_PLT) == 0) &&
+ else if (((req->flags & SYMLOOK_IN_PLT) == 0) &&
(ELF_ST_TYPE(symp->st_info) == STT_FUNC))
break;
/* fallthrough */
default:
continue;
}
- if (name[0] != strp[0] || strcmp(name, strp) != 0)
+ if (req->name[0] != strp[0] || strcmp(req->name, strp) != 0)
continue;
- if (ventry == NULL) {
+ if (req->ventry == NULL) {
if (obj->versyms != NULL) {
verndx = VER_NDX(obj->versyms[symnum]);
if (verndx > obj->vernum) {
* end of the function. If symbol is global (verndx < 2)
* accept it unconditionally.
*/
- if ((flags & SYMLOOK_DLSYM) == 0 && verndx == VER_NDX_GIVEN)
- return symp;
+ if ((req->flags & SYMLOOK_DLSYM) == 0 &&
+ verndx == VER_NDX_GIVEN) {
+ req->sym_out = symp;
+ req->defobj_out = obj;
+ return (0);
+ }
else if (verndx >= VER_NDX_GIVEN) {
if ((obj->versyms[symnum] & VER_NDX_HIDDEN) == 0) {
if (vsymp == NULL)
continue;
}
}
- return symp;
+ req->sym_out = symp;
+ req->defobj_out = obj;
+ return (0);
} else {
if (obj->versyms == NULL) {
- if (object_match_name(obj, ventry->name)) {
+ if (object_match_name(obj, req->ventry->name)) {
_rtld_error("%s: object %s should provide version %s for "
- "symbol %s", obj_rtld.path, obj->path, ventry->name,
- obj->strtab + symnum);
+ "symbol %s", obj_rtld.path, obj->path,
+ req->ventry->name, obj->strtab + symnum);
continue;
}
} else {
obj->path, obj->strtab + symnum, verndx);
continue;
}
- if (obj->vertab[verndx].hash != ventry->hash ||
- strcmp(obj->vertab[verndx].name, ventry->name)) {
+ if (obj->vertab[verndx].hash != req->ventry->hash ||
+ strcmp(obj->vertab[verndx].name, req->ventry->name)) {
/*
* Version does not match. Look if this is a global symbol
* and if it is not hidden. If global symbol (verndx < 2)
* called by dlvsym, because dlvsym looks for a specific
* version and default one is not what dlvsym wants.
*/
- if ((flags & SYMLOOK_DLSYM) ||
+ if ((req->flags & SYMLOOK_DLSYM) ||
(obj->versyms[symnum] & VER_NDX_HIDDEN) ||
(verndx >= VER_NDX_GIVEN))
continue;
}
}
- return symp;
+ req->sym_out = symp;
+ req->defobj_out = obj;
+ return (0);
}
}
- return (vcount == 1) ? vsymp : NULL;
+ if (vcount == 1) {
+ req->sym_out = vsymp;
+ req->defobj_out = obj;
+ return (0);
+ }
+ return (ESRCH);
}
static void
LD_UTRACE(UTRACE_UNLOAD_OBJECT, obj, obj->mapbase, obj->mapsize, 0,
obj->path);
dbg("unloading \"%s\"", obj->path);
+ unload_filtees(root);
munmap(obj->mapbase, obj->mapsize);
linkmap_delete(obj);
*linkp = obj->next;
return NULL;
}
+void
+symlook_init(SymLook *dst, const char *name)
+{
+
+ bzero(dst, sizeof(*dst));
+ dst->name = name;
+ dst->hash = elf_hash(name);
+}
+
+static void
+symlook_init_from_req(SymLook *dst, const SymLook *src)
+{
+
+ dst->name = src->name;
+ dst->hash = src->hash;
+ dst->ventry = src->ventry;
+ dst->flags = src->flags;
+ dst->defobj_out = NULL;
+ dst->sym_out = NULL;
+ dst->lockstate = src->lockstate;
+}
+
#ifdef ENABLE_OSRELDATE
+/*
+ * Overrides for libc_pic-provided functions.
+ */
+
int
__getosreldate(void)
{