Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 24 Jun 2008 00:26:25 +1000 (EST)
From:      Edwin Groothuis <edwin@mavetju.org>
To:        FreeBSD-gnats-submit@FreeBSD.org
Subject:   bin/124906: [patch] teach /usr/bin/ldd about 32 bit objects on a 64 bit architecture
Message-ID:  <20080623142625.6C68D972@k7.mavetju>
Resent-Message-ID: <200806231430.m5NEU2Fc001971@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help

>Number:         124906
>Category:       bin
>Synopsis:       [patch] teach /usr/bin/ldd about 32 bit objects on a 64 bit architecture
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Mon Jun 23 14:30:01 UTC 2008
>Closed-Date:
>Last-Modified:
>Originator:     Edwin Groothuis
>Release:        FreeBSD 7.0-RELEASE-p1 i386
>Organization:
>Environment:
System: FreeBSD k7.mavetju 7.0-RELEASE-p1 FreeBSD 7.0-RELEASE-p1 #2: Wed May 28 08:12:56 EST 2008 edwin@k7.mavetju:/usr/src/sys/i386/compile/k7 i386


>Description:

The ldd utility of a 64 bit architecture doesn't work with 32 bit objects.

[/] root@ed-exigent>uname -a
FreeBSD ed-exigent.barnet.com.au 6.3-RELEASE-p1 FreeBSD 6.3-RELEASE-p1 #0: Wed Feb 13 00:11:33 UTC 2008     root@amd64-builder.daemonology.net:/usr/obj/usr/src/sys/SMP  amd64

[/] root@ed-exigent>ldd `which httpd`
ldd: /usr/local/sbin/httpd: can't read program header
ldd: /usr/local/sbin/httpd: not a dynamic executable

But...

[/] root@ed-exigent>LD_32_TRACE_LOADED_OBJECTS==1 `which httpd`
        libm.so.4 => /lib32//libm.so.4 (0x280c8000)
        libaprutil-1.so.2 => /usr/local/lib/libaprutil-1.so.2 (0x280de000)
        libexpat.so.6 => /usr/local/lib/libexpat.so.6 (0x280f2000)
        libiconv.so.3 => /usr/local/lib/libiconv.so.3 (0x28110000)
        libapr-1.so.2 => /usr/local/lib/libapr-1.so.2 (0x281fd000)
        libcrypt.so.3 => /lib32//libcrypt.so.3 (0x2821d000)
        libpthread.so.2 => not found (0x0)
        libc.so.6 => /lib32//libc.so.6 (0x28235000)
        libpthread.so.2 => /usr/lib32/libpthread.so.2 (0x2830d000)

So it is possible, it just doesn't have the right options.

>How-To-Repeat:

>Fix:

The following patch will teach ldd(1) to handle them properly:

[/] root@ed-exigent>/tmp/ldd  /usr/local/lib/libexpat.so /usr/lib/libssh.so /bin/sh /usr/local/bin/bash
/usr/local/lib/libexpat.so:
ldd: /usr/local/lib/libexpat.so: /usr/local/lib/libexpat.so: unsupported file layout
/usr/local/lib/libexpat.so: exit status 1
/usr/lib/libssh.so:
        libz.so.3 => /lib/libz.so.3 (0x800963000)
        libgssapi.so.8 => /usr/lib/libgssapi.so.8 (0x800a76000)
        libkrb5.so.8 => /usr/lib/libkrb5.so.8 (0x800b85000)
        libasn1.so.8 => /usr/lib/libasn1.so.8 (0x800cc9000)
        libcom_err.so.3 => /usr/lib/libcom_err.so.3 (0x800df2000)
        libmd.so.3 => /lib/libmd.so.3 (0x800ef4000)
        libroken.so.8 => /usr/lib/libroken.so.8 (0x801000000)
        libcrypto.so.4 => /lib/libcrypto.so.4 (0x80110e000)
        libcrypt.so.3 => /lib/libcrypt.so.3 (0x801354000)
/bin/sh:
        libedit.so.5 => /lib/libedit.so.5 (0x800646000)
        libncurses.so.6 => /lib/libncurses.so.6 (0x800760000)
        libc.so.6 => /lib/libc.so.6 (0x8008b9000)
/usr/local/bin/bash:
        libncurses.so.6 => /lib32//libncurses.so.6 (0x28106000)
        libintl.so.6 => /usr/local/lib/libintl.so.6 (0x28145000)
        libiconv.so.3 => /usr/local/lib/libiconv.so.3 (0x2814e000)
        libc.so.6 => /lib32//libc.so.6 (0x2823b000)

It can't do 32 bit libraries because dlopen() can't do it.


Index: ldd.1
===================================================================
--- ldd.1	(revision 179947)
+++ ldd.1	(working copy)
@@ -64,6 +64,11 @@
 It will print a report of all ELF binaries in the current directory,
 which link against libc.so.6:
 .Dl "find . -type f | xargs -n1 file -F " " | grep ELF | cut -f1 -d' ' | xargs ldd -f '%A %o\en' | grep libc.so.6"
+.Sh BUGS
+On 64 bit architectures, dlopen() can't open 32 bit dynamica libraries
+and
+.Nm
+will show the error "unsupported file layout".
 .Sh SEE ALSO
 .Xr ld 1 ,
 .Xr nm 1 ,
Index: ldd.c
===================================================================
--- ldd.c	(revision 179947)
+++ ldd.c	(working copy)
@@ -47,6 +47,45 @@
 
 #include "extern.h"
 
+int is_executable(char *file, int *is_shlib, int *type);
+
+#define TYPE_AOUT	1
+#define TYPE_ELF32	2
+#define TYPE_ELF64	3
+
+#define	ENV_OBJECTS		0
+#define	ENV_OBJECTS_FMT1	1
+#define	ENV_OBJECTS_FMT2	2
+#define	ENV_OBJECTS_PROGNAME	3
+#define	ENV_OBJECTS_ALL		4
+#define ENV_LAST		5
+
+#ifdef __i386__
+const char *env32[ENV_LAST] = {
+	"LD_TRACE_LOADED_OBJECTS",
+	"LD_TRACE_LOADED_OBJECTS_FMT1",
+	"LD_TRACE_LOADED_OBJECTS_FMT2",
+	"LD_TRACE_LOADED_OBJECTS_PROGNAME",
+	"LD_TRACE_LOADED_OBJECTS_ALL",
+};
+const char *env64[ENV_LAST] = {};
+#else
+const char *env64[ENV_LAST] = {
+	"LD_TRACE_LOADED_OBJECTS",
+	"LD_TRACE_LOADED_OBJECTS_FMT1",
+	"LD_TRACE_LOADED_OBJECTS_FMT2",
+	"LD_TRACE_LOADED_OBJECTS_PROGNAME",
+	"LD_TRACE_LOADED_OBJECTS_ALL",
+};
+const char *env32[ENV_LAST] = {
+	"LD_32_TRACE_LOADED_OBJECTS",
+	"LD_32_TRACE_LOADED_OBJECTS_FMT1",
+	"LD_32_TRACE_LOADED_OBJECTS_FMT2",
+	"LD_32_TRACE_LOADED_OBJECTS_PROGNAME",
+	"LD_32_TRACE_LOADED_OBJECTS_ALL",
+};
+#endif
+
 static void
 usage(void)
 {
@@ -61,10 +100,11 @@
 	int		rval;
 	int		c;
 	int		aflag, vflag;
+	const char	**env;
 
 	aflag = vflag = 0;
 
-	while ((c = getopt(argc, argv, "avf:")) != -1) {
+	while ((c = getopt(argc, argv, "23avf:")) != -1) {
 		switch (c) {
 		case 'a':
 			aflag++;
@@ -104,97 +144,38 @@
 	}
 #endif
 
-	/* ld.so magic */
-	setenv("LD_TRACE_LOADED_OBJECTS", "yes", 1);
-	if (fmt1)
-		setenv("LD_TRACE_LOADED_OBJECTS_FMT1", fmt1, 1);
-	if (fmt2)
-		setenv("LD_TRACE_LOADED_OBJECTS_FMT2", fmt2, 1);
-
 	rval = 0;
 	for ( ;  argc > 0;  argc--, argv++) {
-		int	fd;
-		union {
-			struct exec aout;
-			Elf_Ehdr elf;
-		} hdr;
-		int	n;
 		int	status;
-		int	file_ok;
 		int	is_shlib;
+		int	type;
 
-		if ((fd = open(*argv, O_RDONLY, 0)) < 0) {
-			warn("%s", *argv);
+		if (is_executable(*argv, &is_shlib, &type) == 0) {
 			rval |= 1;
 			continue;
 		}
-		if ((n = read(fd, &hdr, sizeof hdr)) == -1) {
-			warn("%s: can't read program header", *argv);
-			(void)close(fd);
-			rval |= 1;
-			continue;
+
+		switch (type) {
+		default:
+		case TYPE_AOUT:		/* XXX */
+		case TYPE_ELF32:
+			env = env32;
+			break;
+		case TYPE_ELF64:
+			env = env64;
+			break;
 		}
 
-		file_ok = 1;
-		is_shlib = 0;
-		if ((size_t)n >= sizeof hdr.aout && !N_BADMAG(hdr.aout)) {
-			/* a.out file */
-			if ((N_GETFLAG(hdr.aout) & EX_DPMASK) != EX_DYNAMIC
-#if 1 /* Compatibility */
-			    || hdr.aout.a_entry < __LDPGSZ
-#endif
-				) {
-				warnx("%s: not a dynamic executable", *argv);
-				file_ok = 0;
-			}
-		} else if ((size_t)n >= sizeof hdr.elf && IS_ELF(hdr.elf)) {
-			Elf_Ehdr ehdr;
-			Elf_Phdr phdr;
-			int dynamic = 0, i;
+		/* ld.so magic */
+		setenv(env[ENV_OBJECTS], "yes", 1);
+		if (fmt1)
+			setenv(env[ENV_OBJECTS_FMT1], fmt1, 1);
+		if (fmt2)
+			setenv(env[ENV_OBJECTS_FMT2], fmt2, 1);
 
-			if (lseek(fd, 0, SEEK_SET) == -1 ||
-			    read(fd, &ehdr, sizeof ehdr) != sizeof ehdr ||
-			    lseek(fd, ehdr.e_phoff, SEEK_SET) == -1
-			   ) {
-				warnx("%s: can't read program header", *argv);
-				file_ok = 0;
-			} else {
-				for (i = 0; i < ehdr.e_phnum; i++) {
-					if (read(fd, &phdr, ehdr.e_phentsize)
-					   != sizeof phdr) {
-						warnx("%s: can't read program header",
-						    *argv);
-						file_ok = 0;
-						break;
-					}
-					if (phdr.p_type == PT_DYNAMIC)
-						dynamic = 1;
-				}
-			}
-			if (!dynamic) {
-				warnx("%s: not a dynamic executable", *argv);
-				file_ok = 0;
-			} else if (hdr.elf.e_type == ET_DYN) {
-				if (hdr.elf.e_ident[EI_OSABI] & ELFOSABI_FREEBSD) {
-					is_shlib = 1;
-				} else {
-					warnx("%s: not a FreeBSD ELF shared "
-					      "object", *argv);
-					file_ok = 0;
-				}
-			}
-		} else {
-			warnx("%s: not a dynamic executable", *argv);
-			file_ok = 0;
-		}
-		(void)close(fd);
-		if (!file_ok) {
-			rval |= 1;
-			continue;
-		}
-
-		setenv("LD_TRACE_LOADED_OBJECTS_PROGNAME", *argv, 1);
-		if (aflag) setenv("LD_TRACE_LOADED_OBJECTS_ALL", "1", 1);
+		setenv(env[ENV_OBJECTS_PROGNAME], *argv, 1);
+		if (aflag)
+			setenv(env[ENV_OBJECTS_ALL], "1", 1);
 		else if (fmt1 == NULL && fmt2 == NULL)
 			/* Default formats */
 			printf("%s:\n", *argv);
@@ -233,3 +214,149 @@
 
 	return rval;
 }
+
+int
+is_executable(char *file, int *is_shlib, int *type)
+{
+	int	fd;
+	union {
+		struct exec aout;
+		Elf_Ehdr elf;
+	} hdr;
+	int	n;
+	int	file_ok = 0;
+	
+	if ((fd = open(file, O_RDONLY, 0)) < 0) {
+		warn("%s", file);
+		return (0);
+	}
+	if ((n = read(fd, &hdr, sizeof hdr)) == -1) {
+		warn("%s: can't read program header", file);
+		goto bye;
+	}
+
+	*is_shlib = 0;
+	if ((size_t)n >= sizeof hdr.aout && !N_BADMAG(hdr.aout)) {
+		/* a.out file */
+		if ((N_GETFLAG(hdr.aout) & EX_DPMASK) != EX_DYNAMIC
+#if 1 /* Compatibility */
+		    || hdr.aout.a_entry < __LDPGSZ
+#endif
+			) {
+			warnx("%s: not a dynamic a.out executable",
+			    file);
+			goto bye;
+		}
+		file_ok = 1;
+		*type = TYPE_AOUT;
+		goto bye;
+	}
+
+	if ((size_t)n >= sizeof hdr.elf && IS_ELF(hdr.elf)) {
+
+		/* 32 bit object */
+		if (hdr.elf.e_ident[EI_CLASS] == 1) {
+			Elf32_Ehdr ehdr;
+			Elf32_Phdr phdr;
+			int dynamic = 0, i;
+
+			if (lseek(fd, 0, SEEK_SET) == -1 ||
+			    read(fd, &ehdr, sizeof ehdr) != sizeof ehdr ||
+			    lseek(fd, ehdr.e_phoff, SEEK_SET) == -1
+			   ) {
+				warnx("%s: can't read program header", file);
+				goto bye;
+			}
+
+			for (i = 0; i < ehdr.e_phnum; i++) {
+				if (read(fd, &phdr, ehdr.e_phentsize)
+				   != sizeof phdr) {
+					warnx("%s: can't read program header",
+					    file);
+					goto bye;
+				}
+				if (phdr.p_type == PT_DYNAMIC)
+					dynamic = 1;
+			}
+
+			if (!dynamic) {
+				warnx("%s: not a dynamic ELF executable",
+				    file);
+				goto bye;
+			}
+
+			if (ehdr.e_type == ET_DYN) {
+				if (ehdr.e_ident[EI_OSABI] &
+				    ELFOSABI_FREEBSD) {
+					*is_shlib = 1;
+					file_ok = 1;
+					goto bye;
+				}
+				warnx("%s: not a FreeBSD ELF shared object",
+				    file);
+				goto bye;
+			}
+
+			*type = TYPE_ELF32;
+			file_ok = 1;
+			goto bye;
+		}
+
+#ifndef __i386__
+		/* 64 bit object */
+		if (hdr.elf.e_ident[EI_CLASS] == 2) {
+			Elf64_Ehdr ehdr;
+			Elf64_Phdr phdr;
+			int dynamic = 0, i;
+
+			if (lseek(fd, 0, SEEK_SET) == -1 ||
+			    read(fd, &ehdr, sizeof ehdr) != sizeof ehdr ||
+			    lseek(fd, ehdr.e_phoff, SEEK_SET) == -1
+			   ) {
+				warnx("%s: can't read program header", file);
+				goto bye;
+			}
+
+			for (i = 0; i < ehdr.e_phnum; i++) {
+				if (read(fd, &phdr, ehdr.e_phentsize)
+				   != sizeof phdr) {
+					warnx("%s: can't read program header",
+					    file);
+					goto bye;
+				}
+				if (phdr.p_type == PT_DYNAMIC)
+					dynamic = 1;
+			}
+
+			if (!dynamic) {
+				warnx("%s: not a dynamic ELF executable",
+				    file);
+				goto bye;
+			}
+
+			if (ehdr.e_type == ET_DYN) {
+				if (ehdr.e_ident[EI_OSABI] &
+				    ELFOSABI_FREEBSD) {
+					*is_shlib = 1;
+					file_ok = 1;
+					goto bye;
+				}
+				warnx("%s: not a FreeBSD ELF shared object",
+				    file);
+				goto bye;
+			}
+
+			*type = TYPE_ELF64;
+			file_ok = 1;
+			goto bye;
+		}
+#endif
+	}
+
+	warnx("%s: not a known dynamic executable", file);
+	goto bye;
+
+bye:
+	(void)close(fd);
+	return (file_ok);
+}
>Release-Note:
>Audit-Trail:
>Unformatted:



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20080623142625.6C68D972>