svn commit: r216695 - in head/libexec/rtld-elf: . amd64 arm i386 ia64 mips powerpc powerpc64 sparc64

Konstantin Belousov kib at FreeBSD.org
Sat Dec 25 08:51:21 UTC 2010


Author: kib
Date: Sat Dec 25 08:51:20 2010
New Revision: 216695
URL: http://svn.freebsd.org/changeset/base/216695

Log:
  Implement support for ELF filters in rtld. Both normal and auxillary
  filters are implemented.
  
  Filtees are loaded on demand, unless LD_LOADFLTR environment variable
  is set or -z loadfltr was specified during the linking. This forces
  rtld to upgrade read-locked rtld_bind_lock to write lock when it
  encounters an object with filter during symbol lookup.
  
  Consolidate common arguments of the symbol lookup functions in the
  SymLook structure.  Track the state of the rtld locks in the
  RtldLockState structure. Pass local RtldLockState through the rtld
  symbol lookup calls to allow lock upgrades.
  
  Reviewed by:	kan
  Tested by:	Mykola Dzham <i levsha me>, nwhitehorn (powerpc)

Modified:
  head/libexec/rtld-elf/amd64/reloc.c
  head/libexec/rtld-elf/arm/reloc.c
  head/libexec/rtld-elf/i386/reloc.c
  head/libexec/rtld-elf/ia64/reloc.c
  head/libexec/rtld-elf/mips/reloc.c
  head/libexec/rtld-elf/powerpc/reloc.c
  head/libexec/rtld-elf/powerpc64/reloc.c
  head/libexec/rtld-elf/rtld.1
  head/libexec/rtld-elf/rtld.c
  head/libexec/rtld-elf/rtld.h
  head/libexec/rtld-elf/rtld_lock.c
  head/libexec/rtld-elf/rtld_lock.h
  head/libexec/rtld-elf/sparc64/reloc.c

Modified: head/libexec/rtld-elf/amd64/reloc.c
==============================================================================
--- head/libexec/rtld-elf/amd64/reloc.c	Sat Dec 25 08:42:38 2010	(r216694)
+++ head/libexec/rtld-elf/amd64/reloc.c	Sat Dec 25 08:51:20 2010	(r216695)
@@ -69,23 +69,28 @@ do_copy_relocations(Obj_Entry *dstobj)
 	    void *dstaddr;
 	    const Elf_Sym *dstsym;
 	    const char *name;
-	    unsigned long hash;
 	    size_t size;
 	    const void *srcaddr;
 	    const Elf_Sym *srcsym;
-	    Obj_Entry *srcobj;
-	    const Ver_Entry *ve;
+	    const Obj_Entry *srcobj, *defobj;
+	    SymLook req;
+	    int res;
 
 	    dstaddr = (void *) (dstobj->relocbase + rela->r_offset);
 	    dstsym = dstobj->symtab + ELF_R_SYM(rela->r_info);
 	    name = dstobj->strtab + dstsym->st_name;
-	    hash = elf_hash(name);
 	    size = dstsym->st_size;
-	    ve = fetch_ventry(dstobj, ELF_R_SYM(rela->r_info));
+	    symlook_init(&req, name);
+	    req.ventry = fetch_ventry(dstobj, ELF_R_SYM(rela->r_info));
 
-	    for (srcobj = dstobj->next;  srcobj != NULL;  srcobj = srcobj->next)
-		if ((srcsym = symlook_obj(name, hash, srcobj, ve, 0)) != NULL)
+	    for (srcobj = dstobj->next;  srcobj != NULL;  srcobj = srcobj->next) {
+		res = symlook_obj(&req, srcobj);
+		if (res == 0) {
+		    srcsym = req.sym_out;
+		    defobj = req.defobj_out;
 		    break;
+		}
+	    }
 
 	    if (srcobj == NULL) {
 		_rtld_error("Undefined symbol \"%s\" referenced from COPY"
@@ -93,7 +98,7 @@ do_copy_relocations(Obj_Entry *dstobj)
 		return -1;
 	    }
 
-	    srcaddr = (const void *) (srcobj->relocbase + srcsym->st_value);
+	    srcaddr = (const void *) (defobj->relocbase + srcsym->st_value);
 	    memcpy(dstaddr, srcaddr, size);
 	}
     }
@@ -113,7 +118,7 @@ init_pltgot(Obj_Entry *obj)
 
 /* Process the non-PLT relocations. */
 int
-reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
+reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, RtldLockState *lockstate)
 {
 	const Elf_Rela *relalim;
 	const Elf_Rela *rela;
@@ -146,7 +151,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry 
 		    const Obj_Entry *defobj;
 
 		    def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
-		      false, cache);
+		      false, cache, lockstate);
 		    if (def == NULL)
 			goto done;
 
@@ -165,7 +170,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry 
 		    const Obj_Entry *defobj;
 
 		    def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
-		      false, cache);
+		      false, cache, lockstate);
 		    if (def == NULL)
 			goto done;
 
@@ -195,7 +200,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry 
 		    const Obj_Entry *defobj;
 
 		    def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
-		      false, cache);
+		      false, cache, lockstate);
 		    if (def == NULL)
 			goto done;
 
@@ -209,7 +214,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry 
 		    const Obj_Entry *defobj;
 
 		    def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
-		      false, cache);
+		      false, cache, lockstate);
 		    if (def == NULL)
 			goto done;
 
@@ -240,7 +245,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry 
 		    const Obj_Entry *defobj;
 
 		    def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
-		      false, cache);
+		      false, cache, lockstate);
 		    if (def == NULL)
 			goto done;
 
@@ -272,7 +277,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry 
 		    const Obj_Entry *defobj;
 
 		    def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
-		      false, cache);
+		      false, cache, lockstate);
 		    if (def == NULL)
 			goto done;
 
@@ -286,7 +291,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry 
 		    const Obj_Entry *defobj;
 
 		    def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
-		      false, cache);
+		      false, cache, lockstate);
 		    if (def == NULL)
 			goto done;
 
@@ -300,7 +305,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry 
 		    const Obj_Entry *defobj;
 
 		    def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
-		      false, cache);
+		      false, cache, lockstate);
 		    if (def == NULL)
 			goto done;
 
@@ -350,7 +355,7 @@ reloc_plt(Obj_Entry *obj)
 
 /* Relocate the jump slots in an object. */
 int
-reloc_jmpslots(Obj_Entry *obj)
+reloc_jmpslots(Obj_Entry *obj, RtldLockState *lockstate)
 {
     const Elf_Rela *relalim;
     const Elf_Rela *rela;
@@ -365,7 +370,8 @@ reloc_jmpslots(Obj_Entry *obj)
 
 	assert(ELF_R_TYPE(rela->r_info) == R_X86_64_JMP_SLOT);
 	where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
-	def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, true, NULL);
+	def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj, true, NULL,
+	    lockstate);
 	if (def == NULL)
 	    return -1;
 	target = (Elf_Addr)(defobj->relocbase + def->st_value + rela->r_addend);

Modified: head/libexec/rtld-elf/arm/reloc.c
==============================================================================
--- head/libexec/rtld-elf/arm/reloc.c	Sat Dec 25 08:42:38 2010	(r216694)
+++ head/libexec/rtld-elf/arm/reloc.c	Sat Dec 25 08:51:20 2010	(r216695)
@@ -36,31 +36,39 @@ do_copy_relocations(Obj_Entry *dstobj)
 	    		void *dstaddr;
 			const Elf_Sym *dstsym;
 			const char *name;
-			unsigned long hash;
 			size_t size;
 			const void *srcaddr;
 			const Elf_Sym *srcsym;
-			Obj_Entry *srcobj;
-			const Ver_Entry *ve;
+			const Obj_Entry *srcobj, *defobj;
+			SymLook req;
+			int res;
 			
 			dstaddr = (void *) (dstobj->relocbase + rel->r_offset);
 			dstsym = dstobj->symtab + ELF_R_SYM(rel->r_info);
 			name = dstobj->strtab + dstsym->st_name;
-			hash = elf_hash(name);
 			size = dstsym->st_size;
-			ve = fetch_ventry(dstobj, ELF_R_SYM(rel->r_info));
-			
-			for (srcobj = dstobj->next;  srcobj != NULL;  srcobj = srcobj->next)
-				if ((srcsym = symlook_obj(name, hash, srcobj, ve, 0)) != NULL)
+
+			symlook_init(&req, name);
+			req.ventry = fetch_ventry(dstobj,
+			    ELF_R_SYM(rel->r_info));
+			for (srcobj = dstobj->next;  srcobj != NULL; 
+			     srcobj = srcobj->next) {
+				res = symlook_obj(&req, srcobj);
+				if (res == 0) {
+					srcsym = req.sym_out;
+					defobj = req.defobj_out;
 					break;
-			
+				}
+			}			
 			if (srcobj == NULL) {
-				_rtld_error("Undefined symbol \"%s\" referenced from COPY"
-				    " relocation in %s", name, dstobj->path);
-				return -1;
+				_rtld_error(
+"Undefined symbol \"%s\" referenced from COPY relocation in %s",
+				    name, dstobj->path);
+				return (-1);
 			}
 			
-			srcaddr = (const void *) (srcobj->relocbase + srcsym->st_value);
+			srcaddr = (const void *)(defobj->relocbase +
+			    srcsym->st_value);
 			memcpy(dstaddr, srcaddr, size);
 		}
 	}
@@ -123,7 +131,8 @@ store_ptr(void *where, Elf_Addr val)
 }
 
 static int
-reloc_nonplt_object(Obj_Entry *obj, const Elf_Rel *rel, SymCache *cache)
+reloc_nonplt_object(Obj_Entry *obj, const Elf_Rel *rel, SymCache *cache,
+    RtldLockState *lockstate)
 {
 	Elf_Addr        *where;
 	const Elf_Sym   *def;
@@ -149,7 +158,8 @@ reloc_nonplt_object(Obj_Entry *obj, cons
 		if (addend & 0x00800000)
 			addend |= 0xff000000;
 		
-		def = find_symdef(symnum, obj, &defobj, false, cache);
+		def = find_symdef(symnum, obj, &defobj, false, cache,
+		    lockstate);
 		if (def == NULL)
 				return -1;
 			tmp = (Elf_Addr)obj->relocbase + def->st_value
@@ -175,7 +185,8 @@ reloc_nonplt_object(Obj_Entry *obj, cons
 
 		case R_ARM_ABS32:	/* word32 B + S + A */
 		case R_ARM_GLOB_DAT:	/* word32 B + S */
-			def = find_symdef(symnum, obj, &defobj, false, cache);
+			def = find_symdef(symnum, obj, &defobj, false, cache,
+			    lockstate);
 			if (def == NULL)
 				return -1;
 			if (__predict_true(RELOC_ALIGNED_P(where))) {
@@ -240,7 +251,7 @@ reloc_nonplt_object(Obj_Entry *obj, cons
  *  * Process non-PLT relocations
  *   */
 int
-reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
+reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, RtldLockState *lockstate)
 {
 	const Elf_Rel *rellim;
 	const Elf_Rel *rel;
@@ -259,7 +270,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry 
 
 	rellim = (const Elf_Rel *)((caddr_t)obj->rel + obj->relsize);
 	for (rel = obj->rel; rel < rellim; rel++) {
-		if (reloc_nonplt_object(obj, rel, cache) < 0)
+		if (reloc_nonplt_object(obj, rel, cache, lockstate) < 0)
 			goto done;
 	}
 	r = 0;
@@ -296,7 +307,7 @@ reloc_plt(Obj_Entry *obj)
  *  * LD_BIND_NOW was set - force relocation for all jump slots
  *   */
 int
-reloc_jmpslots(Obj_Entry *obj)
+reloc_jmpslots(Obj_Entry *obj, RtldLockState *lockstate)
 {
 	const Obj_Entry *defobj;
 	const Elf_Rel *rellim;
@@ -310,7 +321,7 @@ reloc_jmpslots(Obj_Entry *obj)
 		assert(ELF_R_TYPE(rel->r_info) == R_ARM_JUMP_SLOT);
 		where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
 		def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
-		    true, NULL);
+		    true, NULL, lockstate);
 		if (def == NULL) {
 			dbg("reloc_jmpslots: sym not found");
 			return (-1);

Modified: head/libexec/rtld-elf/i386/reloc.c
==============================================================================
--- head/libexec/rtld-elf/i386/reloc.c	Sat Dec 25 08:42:38 2010	(r216694)
+++ head/libexec/rtld-elf/i386/reloc.c	Sat Dec 25 08:51:20 2010	(r216695)
@@ -70,23 +70,28 @@ do_copy_relocations(Obj_Entry *dstobj)
 	    void *dstaddr;
 	    const Elf_Sym *dstsym;
 	    const char *name;
-	    unsigned long hash;
 	    size_t size;
 	    const void *srcaddr;
 	    const Elf_Sym *srcsym;
-	    const Ver_Entry *ve;
-	    Obj_Entry *srcobj;
+	    const Obj_Entry *srcobj, *defobj;
+	    SymLook req;
+	    int res;
 
 	    dstaddr = (void *) (dstobj->relocbase + rel->r_offset);
 	    dstsym = dstobj->symtab + ELF_R_SYM(rel->r_info);
 	    name = dstobj->strtab + dstsym->st_name;
-	    hash = elf_hash(name);
 	    size = dstsym->st_size;
-	    ve = fetch_ventry(dstobj, ELF_R_SYM(rel->r_info));
+	    symlook_init(&req, name);
+	    req.ventry = fetch_ventry(dstobj, ELF_R_SYM(rel->r_info));
 
-	    for (srcobj = dstobj->next;  srcobj != NULL;  srcobj = srcobj->next)
-		if ((srcsym = symlook_obj(name, hash, srcobj, ve, 0)) != NULL)
+	    for (srcobj = dstobj->next;  srcobj != NULL;  srcobj = srcobj->next) {
+		res = symlook_obj(&req, srcobj);
+		if (res == 0) {
+		    srcsym = req.sym_out;
+		    defobj = req.defobj_out;
 		    break;
+		}
+	    }
 
 	    if (srcobj == NULL) {
 		_rtld_error("Undefined symbol \"%s\" referenced from COPY"
@@ -94,7 +99,7 @@ do_copy_relocations(Obj_Entry *dstobj)
 		return -1;
 	    }
 
-	    srcaddr = (const void *) (srcobj->relocbase + srcsym->st_value);
+	    srcaddr = (const void *) (defobj->relocbase + srcsym->st_value);
 	    memcpy(dstaddr, srcaddr, size);
 	}
     }
@@ -114,7 +119,7 @@ init_pltgot(Obj_Entry *obj)
 
 /* Process the non-PLT relocations. */
 int
-reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
+reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, RtldLockState *lockstate)
 {
 	const Elf_Rel *rellim;
 	const Elf_Rel *rel;
@@ -146,7 +151,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry 
 		    const Obj_Entry *defobj;
 
 		    def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
-		      false, cache);
+		      false, cache, lockstate);
 		    if (def == NULL)
 			goto done;
 
@@ -165,7 +170,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry 
 		    const Obj_Entry *defobj;
 
 		    def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
-		      false, cache);
+		      false, cache, lockstate);
 		    if (def == NULL)
 			goto done;
 
@@ -195,7 +200,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry 
 		    const Obj_Entry *defobj;
 
 		    def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
-		      false, cache);
+		      false, cache, lockstate);
 		    if (def == NULL)
 			goto done;
 
@@ -213,7 +218,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry 
 		    const Obj_Entry *defobj;
 
 		    def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
-		      false, cache);
+		      false, cache, lockstate);
 		    if (def == NULL)
 			goto done;
 
@@ -243,7 +248,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry 
 		    const Obj_Entry *defobj;
 
 		    def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
-		      false, cache);
+		      false, cache, lockstate);
 		    if (def == NULL)
 			goto done;
 
@@ -257,7 +262,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry 
 		    const Obj_Entry *defobj;
 
 		    def = find_symdef(ELF_R_SYM(rel->r_info), obj, &defobj,
-		      false, cache);
+		      false, cache, lockstate);
 		    if (def == NULL)
 			goto done;
 
@@ -301,7 +306,7 @@ reloc_plt(Obj_Entry *obj)
 
 /* Relocate the jump slots in an object. */
 int
-reloc_jmpslots(Obj_Entry *obj)
+reloc_jmpslots(Obj_Entry *obj, RtldLockState *lockstate)
 {
     const Elf_Rel *rellim;
     const Elf_Rel *rel;
@@ -316,7 +321,8 @@ reloc_jmpslots(Obj_Entry *obj)
 
 	assert(ELF_R_TYPE(rel->r_info) == R_386_JMP_SLOT);
 	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)
 	    return -1;
 	target = (Elf_Addr)(defobj->relocbase + def->st_value);

Modified: head/libexec/rtld-elf/ia64/reloc.c
==============================================================================
--- head/libexec/rtld-elf/ia64/reloc.c	Sat Dec 25 08:42:38 2010	(r216694)
+++ head/libexec/rtld-elf/ia64/reloc.c	Sat Dec 25 08:51:20 2010	(r216695)
@@ -151,7 +151,7 @@ free_fptrs(Obj_Entry *obj, bool mapped)
 /* Relocate a non-PLT object with addend. */
 static int
 reloc_non_plt_obj(Obj_Entry *obj_rtld, Obj_Entry *obj, const Elf_Rela *rela,
-		  SymCache *cache)
+    SymCache *cache, RtldLockState *lockstate)
 {
 	struct fptr **fptrs;
 	Elf_Addr *where = (Elf_Addr *) (obj->relocbase + rela->r_offset);
@@ -172,7 +172,7 @@ reloc_non_plt_obj(Obj_Entry *obj_rtld, O
 		Elf_Addr target;
 
 		def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
-				  false, cache);
+		    false, cache, lockstate);
 		if (def == NULL)
 			return -1;
 
@@ -195,7 +195,7 @@ reloc_non_plt_obj(Obj_Entry *obj_rtld, O
 		int sym_index;
 
 		def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
-				  true, cache);
+		    true, cache, lockstate);
 		if (def == NULL) {
 			/*
 			 * XXX r_debug_state is problematic and find_symdef()
@@ -254,7 +254,7 @@ reloc_non_plt_obj(Obj_Entry *obj_rtld, O
 		Elf_Addr target, gp;
 
 		def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
-				  false, cache);
+		    false, cache, lockstate);
 		if (def == NULL)
 			return -1;
 
@@ -277,7 +277,7 @@ reloc_non_plt_obj(Obj_Entry *obj_rtld, O
 		const Obj_Entry *defobj;
 
 		def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
-				  false, cache);
+		    false, cache, lockstate);
 		if (def == NULL)
 			return -1;
 
@@ -290,7 +290,7 @@ reloc_non_plt_obj(Obj_Entry *obj_rtld, O
 		const Obj_Entry *defobj;
 
 		def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
-				  false, cache);
+		    false, cache, lockstate);
 		if (def == NULL)
 			return -1;
 
@@ -303,7 +303,7 @@ reloc_non_plt_obj(Obj_Entry *obj_rtld, O
 		const Obj_Entry *defobj;
 
 		def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
-				  false, cache);
+		    false, cache, lockstate);
 		if (def == NULL)
 			return -1;
 
@@ -342,7 +342,7 @@ reloc_non_plt_obj(Obj_Entry *obj_rtld, O
 
 /* Process the non-PLT relocations. */
 int
-reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
+reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, RtldLockState *lockstate)
 {
 	const Elf_Rel *rellim;
 	const Elf_Rel *rel;
@@ -368,14 +368,15 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry 
 		locrela.r_info = rel->r_info;
 		locrela.r_offset = rel->r_offset;
 		locrela.r_addend = 0;
-		if (reloc_non_plt_obj(obj_rtld, obj, &locrela, cache))
+		if (reloc_non_plt_obj(obj_rtld, obj, &locrela, cache,
+		    lockstate))
 			goto done;
 	}
 
 	/* Perform relocations with addend if there are any: */
 	relalim = (const Elf_Rela *) ((caddr_t) obj->rela + obj->relasize);
 	for (rela = obj->rela;  obj->rela != NULL && rela < relalim;  rela++) {
-		if (reloc_non_plt_obj(obj_rtld, obj, rela, cache))
+		if (reloc_non_plt_obj(obj_rtld, obj, rela, cache, lockstate))
 			goto done;
 	}
 
@@ -436,7 +437,7 @@ reloc_plt(Obj_Entry *obj)
 
 /* Relocate the jump slots in an object. */
 int
-reloc_jmpslots(Obj_Entry *obj)
+reloc_jmpslots(Obj_Entry *obj, RtldLockState *lockstate)
 {
 	if (obj->jmpslots_done)
 		return 0;
@@ -455,7 +456,7 @@ reloc_jmpslots(Obj_Entry *obj)
 			assert(ELF_R_TYPE(rel->r_info) == R_IA_64_IPLTLSB);
 			where = (Elf_Addr *)(obj->relocbase + rel->r_offset);
 			def = find_symdef(ELF_R_SYM(rel->r_info), obj,
-					  &defobj, true, NULL);
+			    &defobj, true, NULL, lockstate);
 			if (def == NULL)
 				return -1;
 			reloc_jmpslot(where,
@@ -476,7 +477,7 @@ reloc_jmpslots(Obj_Entry *obj)
 
 			where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
 			def = find_symdef(ELF_R_SYM(rela->r_info), obj,
-					  &defobj, true, NULL);
+			    &defobj, true, NULL, lockstate);
 			if (def == NULL)
 				return -1;
 			reloc_jmpslot(where,

Modified: head/libexec/rtld-elf/mips/reloc.c
==============================================================================
--- head/libexec/rtld-elf/mips/reloc.c	Sat Dec 25 08:42:38 2010	(r216694)
+++ head/libexec/rtld-elf/mips/reloc.c	Sat Dec 25 08:51:20 2010	(r216695)
@@ -238,7 +238,8 @@ _mips_rtld_bind(Obj_Entry *obj, Elf_Size
         const Obj_Entry *defobj;
         Elf_Addr target;
 
-        def = find_symdef(reloff, obj, &defobj, SYMLOOK_IN_PLT, NULL);
+        def = find_symdef(reloff, obj, &defobj, SYMLOOK_IN_PLT, NULL,
+	    NULL);
         if (def == NULL)
 		_rtld_error("bind failed no symbol");
 
@@ -253,7 +254,7 @@ _mips_rtld_bind(Obj_Entry *obj, Elf_Size
 }
 
 int
-reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
+reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, RtldLockState *lockstate)
 {
 	const Elf_Rel *rel;
 	const Elf_Rel *rellim;
@@ -312,7 +313,8 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry 
 			 * to 0 if there are non-PLT references, but older
 			 * versions of GNU ld do not do this.
 			 */
-			def = find_symdef(i, obj, &defobj, false, NULL);
+			def = find_symdef(i, obj, &defobj, false, NULL,
+			    lockstate);
 			if (def == NULL)
 				return -1;
 			*got = def->st_value + (Elf_Addr)defobj->relocbase;
@@ -353,7 +355,8 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry 
 			}
 		} else {
 			/* TODO: add cache here */
-			def = find_symdef(i, obj, &defobj, false, NULL);
+			def = find_symdef(i, obj, &defobj, false, NULL,
+			    lockstate);
 			if (def == NULL) {
 				dbg("Warning4, cant find symbole %d", i);
 				return -1;
@@ -487,7 +490,7 @@ reloc_plt(Obj_Entry *obj)
  * LD_BIND_NOW was set - force relocation for all jump slots
  */
 int
-reloc_jmpslots(Obj_Entry *obj)
+reloc_jmpslots(Obj_Entry *obj, RtldLockState *lockstate)
 {
 	/* Do nothing */
 	obj->jmpslots_done = true;

Modified: head/libexec/rtld-elf/powerpc/reloc.c
==============================================================================
--- head/libexec/rtld-elf/powerpc/reloc.c	Sat Dec 25 08:42:38 2010	(r216694)
+++ head/libexec/rtld-elf/powerpc/reloc.c	Sat Dec 25 08:51:20 2010	(r216695)
@@ -75,12 +75,12 @@ do_copy_relocations(Obj_Entry *dstobj)
 		void *dstaddr;
 		const Elf_Sym *dstsym;
 		const char *name;
-		unsigned long hash;
 		size_t size;
 		const void *srcaddr;
 		const Elf_Sym *srcsym = NULL;
-		Obj_Entry *srcobj;
-		const Ver_Entry *ve;
+		const Obj_Entry *srcobj, *defobj;
+		SymLook req;
+		int res;
 
 		if (ELF_R_TYPE(rela->r_info) != R_PPC_COPY) {
 			continue;
@@ -89,14 +89,16 @@ do_copy_relocations(Obj_Entry *dstobj)
 		dstaddr = (void *) (dstobj->relocbase + rela->r_offset);
 		dstsym = dstobj->symtab + ELF_R_SYM(rela->r_info);
 		name = dstobj->strtab + dstsym->st_name;
-		hash = elf_hash(name);
 		size = dstsym->st_size;
-		ve = fetch_ventry(dstobj, ELF_R_SYM(rela->r_info));
+		symlook_init(&req, name);
+		req.ventry = fetch_ventry(dstobj, ELF_R_SYM(rela->r_info));
 
 		for (srcobj = dstobj->next;  srcobj != NULL;
 		     srcobj = srcobj->next) {
-			if ((srcsym = symlook_obj(name, hash, srcobj, ve, 0))
-			    != NULL) {
+			res = symlook_obj(&req, srcobj);
+			if (res == 0) {
+				srcsym = req.sym_out;
+				defobj = req.defobj_out;
 				break;
 			}
 		}
@@ -108,7 +110,7 @@ do_copy_relocations(Obj_Entry *dstobj)
 			return (-1);
 		}
 
-		srcaddr = (const void *) (srcobj->relocbase+srcsym->st_value);
+		srcaddr = (const void *) (defobj->relocbase+srcsym->st_value);
 		memcpy(dstaddr, srcaddr, size);
 		dbg("copy_reloc: src=%p,dst=%p,size=%d\n",srcaddr,dstaddr,size);
 	}
@@ -157,7 +159,7 @@ reloc_non_plt_self(Elf_Dyn *dynp, Elf_Ad
  */
 static int
 reloc_nonplt_object(Obj_Entry *obj_rtld, Obj_Entry *obj, const Elf_Rela *rela,
-		    SymCache *cache)
+    SymCache *cache, RtldLockState *lockstate)
 {
 	Elf_Addr        *where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
 	const Elf_Sym   *def;
@@ -172,7 +174,7 @@ reloc_nonplt_object(Obj_Entry *obj_rtld,
         case R_PPC_ADDR32:    /* word32 S + A */
         case R_PPC_GLOB_DAT:  /* word32 S + A */
 		def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
-				  false, cache);
+		    false, cache, lockstate);
 		if (def == NULL) {
 			return (-1);
 		}
@@ -219,7 +221,7 @@ reloc_nonplt_object(Obj_Entry *obj_rtld,
 
 	case R_PPC_DTPMOD32:
 		def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
-		    false, cache);
+		    false, cache, lockstate);
 
 		if (def == NULL)
 			return (-1);
@@ -230,7 +232,7 @@ reloc_nonplt_object(Obj_Entry *obj_rtld,
 
 	case R_PPC_TPREL32:
 		def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
-		    false, cache);
+		    false, cache, lockstate);
 
 		if (def == NULL)
 			return (-1);
@@ -259,7 +261,7 @@ reloc_nonplt_object(Obj_Entry *obj_rtld,
 		
 	case R_PPC_DTPREL32:
 		def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
-		    false, cache);
+		    false, cache, lockstate);
 
 		if (def == NULL)
 			return (-1);
@@ -283,7 +285,7 @@ reloc_nonplt_object(Obj_Entry *obj_rtld,
  * Process non-PLT relocations
  */
 int
-reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
+reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, RtldLockState *lockstate)
 {
 	const Elf_Rela *relalim;
 	const Elf_Rela *rela;
@@ -307,7 +309,8 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry 
 	 */
 	relalim = (const Elf_Rela *)((caddr_t)obj->rela + obj->relasize);
 	for (rela = obj->rela; rela < relalim; rela++) {
-		if (reloc_nonplt_object(obj_rtld, obj, rela, cache) < 0)
+		if (reloc_nonplt_object(obj_rtld, obj, rela, cache, lockstate)
+		    < 0)
 			goto done;
 	}
 	r = 0;
@@ -401,7 +404,7 @@ reloc_plt(Obj_Entry *obj)
  * LD_BIND_NOW was set - force relocation for all jump slots
  */
 int
-reloc_jmpslots(Obj_Entry *obj)
+reloc_jmpslots(Obj_Entry *obj, RtldLockState *lockstate)
 {
 	const Obj_Entry *defobj;
 	const Elf_Rela *relalim;
@@ -415,7 +418,7 @@ reloc_jmpslots(Obj_Entry *obj)
 		assert(ELF_R_TYPE(rela->r_info) == R_PPC_JMP_SLOT);
 		where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
 		def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
-		   true, NULL);
+		    true, NULL, lockstate);
 		if (def == NULL) {
 			dbg("reloc_jmpslots: sym not found");
 			return (-1);

Modified: head/libexec/rtld-elf/powerpc64/reloc.c
==============================================================================
--- head/libexec/rtld-elf/powerpc64/reloc.c	Sat Dec 25 08:42:38 2010	(r216694)
+++ head/libexec/rtld-elf/powerpc64/reloc.c	Sat Dec 25 08:51:20 2010	(r216695)
@@ -69,12 +69,12 @@ do_copy_relocations(Obj_Entry *dstobj)
 		void *dstaddr;
 		const Elf_Sym *dstsym;
 		const char *name;
-		unsigned long hash;
 		size_t size;
 		const void *srcaddr;
 		const Elf_Sym *srcsym = NULL;
-		Obj_Entry *srcobj;
-		const Ver_Entry *ve;
+		const Obj_Entry *srcobj, *defobj;
+		SymLook req;
+		int res;
 
 		if (ELF_R_TYPE(rela->r_info) != R_PPC_COPY) {
 			continue;
@@ -83,14 +83,16 @@ do_copy_relocations(Obj_Entry *dstobj)
 		dstaddr = (void *) (dstobj->relocbase + rela->r_offset);
 		dstsym = dstobj->symtab + ELF_R_SYM(rela->r_info);
 		name = dstobj->strtab + dstsym->st_name;
-		hash = elf_hash(name);
 		size = dstsym->st_size;
-		ve = fetch_ventry(dstobj, ELF_R_SYM(rela->r_info));
+		symlook_init(&req, name);
+		req.ventry = fetch_ventry(dstobj, ELF_R_SYM(rela->r_info));
 
 		for (srcobj = dstobj->next;  srcobj != NULL;
 		     srcobj = srcobj->next) {
-			if ((srcsym = symlook_obj(name, hash, srcobj, ve, 0))
-			    != NULL) {
+			res = symlook_obj(&req, srcobj);
+			if (res == 0) {
+				srcsym = req.sym_out;
+				defobj = req.defobj_out;
 				break;
 			}
 		}
@@ -102,7 +104,7 @@ do_copy_relocations(Obj_Entry *dstobj)
 			return (-1);
 		}
 
-		srcaddr = (const void *) (srcobj->relocbase+srcsym->st_value);
+		srcaddr = (const void *) (defobj->relocbase+srcsym->st_value);
 		memcpy(dstaddr, srcaddr, size);
 		dbg("copy_reloc: src=%p,dst=%p,size=%zd\n",srcaddr,dstaddr,size);
 	}
@@ -151,7 +153,7 @@ reloc_non_plt_self(Elf_Dyn *dynp, Elf_Ad
  */
 static int
 reloc_nonplt_object(Obj_Entry *obj_rtld, Obj_Entry *obj, const Elf_Rela *rela,
-		    SymCache *cache)
+    SymCache *cache, RtldLockState *lockstate)
 {
 	Elf_Addr        *where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
 	const Elf_Sym   *def;
@@ -166,7 +168,7 @@ reloc_nonplt_object(Obj_Entry *obj_rtld,
         case R_PPC64_ADDR64:    /* doubleword64 S + A */
         case R_PPC_GLOB_DAT:
 		def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
-				  false, cache);
+		    false, cache, lockstate);
 		if (def == NULL) {
 			return (-1);
 		}
@@ -213,7 +215,7 @@ reloc_nonplt_object(Obj_Entry *obj_rtld,
 
 	case R_PPC64_DTPMOD64:
 		def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
-		    false, cache);
+		    false, cache, lockstate);
 
 		if (def == NULL)
 			return (-1);
@@ -224,7 +226,7 @@ reloc_nonplt_object(Obj_Entry *obj_rtld,
 
 	case R_PPC64_TPREL64:
 		def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
-		    false, cache);
+		    false, cache, lockstate);
 
 		if (def == NULL)
 			return (-1);
@@ -253,7 +255,7 @@ reloc_nonplt_object(Obj_Entry *obj_rtld,
 		
 	case R_PPC64_DTPREL64:
 		def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
-		    false, cache);
+		    false, cache, lockstate);
 
 		if (def == NULL)
 			return (-1);
@@ -277,7 +279,7 @@ reloc_nonplt_object(Obj_Entry *obj_rtld,
  * Process non-PLT relocations
  */
 int
-reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
+reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, RtldLockState *lockstate)
 {
 	const Elf_Rela *relalim;
 	const Elf_Rela *rela;
@@ -304,7 +306,8 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry 
 	 */
 	relalim = (const Elf_Rela *)((caddr_t)obj->rela + obj->relasize);
 	for (rela = obj->rela; rela < relalim; rela++) {
-		if (reloc_nonplt_object(obj_rtld, obj, rela, cache) < 0)
+		if (reloc_nonplt_object(obj_rtld, obj, rela, cache, lockstate)
+		    < 0)
 			goto done;
 	}
 	r = 0;
@@ -376,7 +379,7 @@ reloc_plt(Obj_Entry *obj)
  * LD_BIND_NOW was set - force relocation for all jump slots
  */
 int
-reloc_jmpslots(Obj_Entry *obj)
+reloc_jmpslots(Obj_Entry *obj, RtldLockState *lockstate)
 {
 	const Obj_Entry *defobj;
 	const Elf_Rela *relalim;
@@ -390,7 +393,7 @@ reloc_jmpslots(Obj_Entry *obj)
 		assert(ELF_R_TYPE(rela->r_info) == R_PPC_JMP_SLOT);
 		where = (Elf_Addr *)(obj->relocbase + rela->r_offset);
 		def = find_symdef(ELF_R_SYM(rela->r_info), obj, &defobj,
-		   true, NULL);
+		    true, NULL, lockstate);
 		if (def == NULL) {
 			dbg("reloc_jmpslots: sym not found");
 			return (-1);

Modified: head/libexec/rtld-elf/rtld.1
==============================================================================
--- head/libexec/rtld-elf/rtld.1	Sat Dec 25 08:42:38 2010	(r216694)
+++ head/libexec/rtld-elf/rtld.1	Sat Dec 25 08:51:20 2010	(r216695)
@@ -221,6 +221,14 @@ If set,
 .Nm
 will log events such as the loading and unloading of shared objects via
 .Xr utrace 2 .
+.Pp
+.It Ev LD_LOADFLTR
+If set,
+.Nm
+will process the filtee dependencies of the loaded objects immediately,
+instead of postponing it until required.
+Normally, the filtees are opened at the time of the first symbol resolution
+from the filter object.
 .El
 .Sh FILES
 .Bl -tag -width ".Pa /var/run/ld-elf32.so.hints" -compact

Modified: head/libexec/rtld-elf/rtld.c
==============================================================================
--- head/libexec/rtld-elf/rtld.c	Sat Dec 25 08:42:38 2010	(r216694)
+++ head/libexec/rtld-elf/rtld.c	Sat Dec 25 08:51:20 2010	(r216695)
@@ -71,16 +71,6 @@ typedef void (*func_ptr_type)();
 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 *basename(const char *);
@@ -91,6 +81,8 @@ static void digest_dynamic2(Obj_Entry *,
 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 *);
@@ -106,12 +98,14 @@ static void initlist_add_neededs(Needed_
 static void initlist_add_objects(Obj_Entry *, Obj_Entry **, Objlist *);
 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 Obj_Entry *obj_from_addr(const void *);
-static void objlist_call_fini(Objlist *, Obj_Entry *, int *);
-static void objlist_call_init(Objlist *, int *);
+static void objlist_call_fini(Objlist *, Obj_Entry *, RtldLockState *);
+static void objlist_call_init(Objlist *, RtldLockState *);
 static void objlist_clear(Objlist *);
 static Objlist_Entry *objlist_find(Objlist *, const Obj_Entry *);
 static void objlist_init(Objlist *);
@@ -119,20 +113,18 @@ static void objlist_push_head(Objlist *,
 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 *);
@@ -157,6 +149,7 @@ void r_debug_state(struct r_debug *, str
 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
@@ -300,7 +293,7 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_
     Obj_Entry *obj;
     Obj_Entry **preload_tail;
     Objlist initlist;
-    int lockstate;
+    RtldLockState lockstate;
 
     /*
      * On entry, the dynamic linker itself has not been relocated yet.
@@ -346,7 +339,8 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_
     if (!trust) {
         if (unsetenv(LD_ "PRELOAD") || unsetenv(LD_ "LIBMAP") ||
 	    unsetenv(LD_ "LIBRARY_PATH") || unsetenv(LD_ "LIBMAP_DISABLE") ||
-	    unsetenv(LD_ "DEBUG") || unsetenv(LD_ "ELF_HINTS_PATH")) {
+	    unsetenv(LD_ "DEBUG") || unsetenv(LD_ "ELF_HINTS_PATH") ||
+	    unsetenv(LD_ "LOADFLTR")) {
 		_rtld_error("environment corrupt; aborting");
 		die();
 	}
@@ -357,9 +351,10 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_
     ld_library_path = getenv(LD_ "LIBRARY_PATH");
     ld_preload = getenv(LD_ "PRELOAD");
     ld_elf_hints_path = getenv(LD_ "ELF_HINTS_PATH");
+    ld_loadfltr = getenv(LD_ "LOADFLTR") != NULL;
     dangerous_ld_env = libmap_disable || (libmap_override != NULL) ||
 	(ld_library_path != NULL) || (ld_preload != NULL) ||
-	(ld_elf_hints_path != NULL);
+	(ld_elf_hints_path != NULL) || ld_loadfltr;
     ld_tracing = getenv(LD_ "TRACE_LOADED_OBJECTS");
     ld_utrace = getenv(LD_ "UTRACE");
 
@@ -373,6 +368,9 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_
     dbg("RTLD dynamic = %p", obj_rtld.dynamic);
     dbg("RTLD pltgot  = %p", obj_rtld.pltgot);
 
+    dbg("initializing thread locks");
+    lockdflt_init();
+
     /*
      * Load the main program, or process its program header if it is
      * already loaded.
@@ -498,7 +496,7 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_
     allocate_initial_tls(obj_list);
 
     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");
@@ -515,19 +513,21 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_
     set_program_var("environ", env);
     set_program_var("__elf_aux_vector", aux);
 
-    dbg("initializing thread locks");
-    lockdflt_init();
-
     /* Make a list of init functions to call. */
     objlist_init(&initlist);
     initlist_add_objects(obj_list, preload_tail, &initlist);
 
     r_debug_state(NULL, &obj_main->linkmap); /* say hello to gdb! */
 
-    lockstate = wlock_acquire(rtld_bind_lock);
+    wlock_acquire(rtld_bind_lock, &lockstate);
     objlist_call_init(&initlist, &lockstate);
     objlist_clear(&initlist);
-    wlock_release(rtld_bind_lock, lockstate);
+    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);
 
     dbg("transferring control to program entry point = %p", obj_main->entry);
 

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-head mailing list