Sat Oct 4 09:37:12 2008 UTC ()
lib/39649: dlsym(3) does not follow dependencies

Pull across code from FreeBSD to do a search of the passed object and it's
NEEDED objects (dependencies).

Reviewed by gimpy.


(skrll)
diff -r1.121 -r1.122 src/libexec/ld.elf_so/rtld.c
diff -r1.78 -r1.79 src/libexec/ld.elf_so/rtld.h
diff -r1.46 -r1.47 src/libexec/ld.elf_so/symbol.c

cvs diff -r1.121 -r1.122 src/libexec/ld.elf_so/rtld.c (expand / switch to context diff)
--- src/libexec/ld.elf_so/rtld.c 2008/09/27 03:52:05 1.121
+++ src/libexec/ld.elf_so/rtld.c 2008/10/04 09:37:12 1.122
@@ -1,4 +1,4 @@
-/*	$NetBSD: rtld.c,v 1.121 2008/09/27 03:52:05 macallan Exp $	 */
+/*	$NetBSD: rtld.c,v 1.122 2008/10/04 09:37:12 skrll Exp $	 */
 
 /*
  * Copyright 1996 John D. Polstra.
@@ -40,7 +40,7 @@
 
 #include <sys/cdefs.h>
 #ifndef lint
-__RCSID("$NetBSD: rtld.c,v 1.121 2008/09/27 03:52:05 macallan Exp $");
+__RCSID("$NetBSD: rtld.c,v 1.122 2008/10/04 09:37:12 skrll Exp $");
 #endif /* not lint */
 
 #include <err.h>
@@ -889,12 +889,14 @@
 			def = _rtld_symlook_list(name, hash, &_rtld_list_main,
 			    &defobj, false);
 		} else {
-			/*
-			 * XXX - This isn't correct.  The search should include
-			 * the whole DAG rooted at the given object.
-			 */
-			def = _rtld_symlook_obj(name, hash, obj, false);
-			defobj = obj;
+			Needed_Entry fake;
+
+			/* Search the object and all the libraries loaded by it. */
+			fake.next = NULL;
+			fake.obj = (Obj_Entry *)obj;
+			fake.name = 0;
+			def = _rtld_symlook_needed(name, hash, &fake, &defobj,
+			    false);
 		}
 		break;
 	}

cvs diff -r1.78 -r1.79 src/libexec/ld.elf_so/rtld.h (expand / switch to context diff)
--- src/libexec/ld.elf_so/rtld.h 2008/06/03 19:32:32 1.78
+++ src/libexec/ld.elf_so/rtld.h 2008/10/04 09:37:12 1.79
@@ -1,4 +1,4 @@
-/*	$NetBSD: rtld.h,v 1.78 2008/06/03 19:32:32 ad Exp $	 */
+/*	$NetBSD: rtld.h,v 1.79 2008/10/04 09:37:12 skrll Exp $	 */
 
 /*
  * Copyright 1996 John D. Polstra.
@@ -274,6 +274,8 @@
     const Objlist *, const Obj_Entry **, bool);
 const Elf_Sym *_rtld_symlook_default(const char *, unsigned long,
     const Obj_Entry *, const Obj_Entry **, bool);
+const Elf_Sym *_rtld_symlook_needed(const char *, unsigned long,
+    const Needed_Entry *, const Obj_Entry **, bool);
 
 /* map_object.c */
 Obj_Entry *_rtld_map_object(const char *, int, const struct stat *);

cvs diff -r1.46 -r1.47 src/libexec/ld.elf_so/symbol.c (expand / switch to context diff)
--- src/libexec/ld.elf_so/symbol.c 2008/07/24 04:39:25 1.46
+++ src/libexec/ld.elf_so/symbol.c 2008/10/04 09:37:12 1.47
@@ -1,4 +1,4 @@
-/*	$NetBSD: symbol.c,v 1.46 2008/07/24 04:39:25 matt Exp $	 */
+/*	$NetBSD: symbol.c,v 1.47 2008/10/04 09:37:12 skrll Exp $	 */
 
 /*
  * Copyright 1996 John D. Polstra.
@@ -40,7 +40,7 @@
 
 #include <sys/cdefs.h>
 #ifndef lint
-__RCSID("$NetBSD: symbol.c,v 1.46 2008/07/24 04:39:25 matt Exp $");
+__RCSID("$NetBSD: symbol.c,v 1.47 2008/10/04 09:37:12 skrll Exp $");
 #endif /* not lint */
 
 #include <err.h>
@@ -132,6 +132,56 @@
 	}
 	if (def != NULL)
 		*defobj_out = defobj;
+	return def;
+}
+
+/*
+ * Search the symbol table of a shared object and all objects needed by it for
+ * a symbol of the given name. Search order is breadth-first. Returns a pointer
+ * to the symbol, or NULL if no definition was found.
+ */
+const Elf_Sym *
+_rtld_symlook_needed(const char *name, unsigned long hash,
+    const Needed_Entry *needed, const Obj_Entry **defobj_out, bool inplt)
+{
+	const Elf_Sym *def, *def_w;
+	const Needed_Entry *n;
+	const Obj_Entry *obj, *defobj, *defobj1;
+
+	def = def_w = NULL;
+	defobj = NULL;
+	for (n = needed; n != NULL; n = n->next) {
+		if ((obj = n->obj) == NULL ||
+		     (def = _rtld_symlook_obj(name, hash, obj, inplt)) == NULL)
+			continue;
+		defobj = obj;
+		if (ELF_ST_BIND(def->st_info) != STB_WEAK) {
+			*defobj_out = defobj;
+
+			return (def);
+		}
+	}
+	/*
+	 * Either the symbol definition has not been found in directly needed
+	 * objects, or the found symbol is weak.
+	 */
+	for (n = needed; n != NULL; n = n->next) {
+		if ((obj = n->obj) == NULL)
+			continue;
+		def_w = _rtld_symlook_needed(name, hash, obj->needed, &defobj1,
+		    inplt);
+		if (def_w == NULL)
+			continue;
+		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;
 }