Tweak the support for using ldd on 32-bit objects a bit further.

Specifically, build a 32-bit /usr/bin/ldd32 on amd64 which handles 32-bit
objects.  Since it is a 32-bit binary, it can fork a child process which
can dlopen() a 32-bit shared library.  The current 32-bit support in ldd
can't do this because it does the dlopen() from a 64-bit process.  In order
to preserve an intuitive interface for users, the ldd binary automatically
execs /usr/bin/ldd32 for 32-bit objects.  The end result is that ldd on
amd64 now transparently handles 32-bit shared libraries in addition to
32-bit binaries.

Submitted by:	ps (indirectly)
This commit is contained in:
John Baldwin 2008-08-01 21:52:41 +00:00
parent a05cf8c6db
commit e68ed79390
4 changed files with 70 additions and 38 deletions

View File

@ -482,6 +482,8 @@ build32:
.for _t in obj depend all
cd ${.CURDIR}/libexec/rtld-elf; \
PROG=ld-elf32.so.1 ${LIB32WMAKE} ${_t}
cd ${.CURDIR}/usr.bin/ldd; \
PROG=ldd32 ${LIB32WMAKE} ${_t}
.endfor
distribute32 install32:
@ -501,6 +503,7 @@ distribute32 install32:
cd ${.CURDIR}/secure/lib; ${LIB32IMAKE} ${.TARGET:S/32$//}
.endif
cd ${.CURDIR}/libexec/rtld-elf; PROG=ld-elf32.so.1 ${LIB32IMAKE} ${.TARGET:S/32$//}
cd ${.CURDIR}/usr.bin/ldd; PROG=ldd32 ${LIB32IMAKE} ${.TARGET:S/32$//}
.endif

View File

@ -1,6 +1,6 @@
# $FreeBSD$
PROG= ldd
PROG?= ldd
SRCS= ldd.c
.if ${MACHINE_ARCH} == "i386"
SRCS+= sods.c

View File

@ -64,12 +64,6 @@ option.
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() cannot open 32 bit dynamic libraries,
so
.Nm
will show the error
.Qq "unsupported file layout" .
.Sh SEE ALSO
.Xr ld 1 ,
.Xr nm 1 ,

View File

@ -44,10 +44,17 @@ __FBSDID("$FreeBSD$");
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "extern.h"
#ifdef COMPAT_32BIT
#define LD_ "LD_32_"
#else
#define LD_ "LD_"
#endif
/*
* 32-bit ELF data structures can only be used if the system header[s] declare
* them. There is no official macro for determining whether they are declared,
@ -66,30 +73,60 @@ static void usage(void);
#define TYPE_ELF 2 /* Architecture default */
#if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED)
#define TYPE_ELF32 3 /* Explicit 32 bits on architectures >32 bits */
#endif
#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
#define _PATH_LDD32 "/usr/bin/ldd32"
const char *envdef[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",
};
#if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED)
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",
};
static int
execldd32(char *file, char *fmt1, char *fmt2, int aflag, int vflag)
{
char *argv[8];
int i, rval, status;
unsetenv(LD_ "TRACE_LOADED_OBJECTS");
rval = 0;
i = 0;
argv[i++] = strdup(_PATH_LDD32);
if (aflag)
argv[i++] = strdup("-a");
if (vflag)
argv[i++] = strdup("-v");
if (fmt1) {
argv[i++] = strdup("-f");
argv[i++] = strdup(fmt1);
}
if (fmt2) {
argv[i++] = strdup("-f");
argv[i++] = strdup(fmt2);
}
argv[i++] = strdup(file);
argv[i++] = NULL;
switch (fork()) {
case -1:
err(1, "fork");
break;
case 0:
execv(_PATH_LDD32, argv);
warn("%s", _PATH_LDD32);
_exit(1);
break;
default:
if (wait(&status) <= 0) {
rval = 1;
} else if (WIFSIGNALED(status)) {
rval = 1;
} else if (WIFEXITED(status) && WEXITSTATUS(status)) {
rval = 1;
}
break;
}
while (i--)
free(argv[i]);
setenv(LD_ "TRACE_LOADED_OBJECTS", "yes", 1);
return (rval);
}
#endif
int
@ -144,7 +181,6 @@ main(int argc, char *argv[])
rval = 0;
for (; argc > 0; argc--, argv++) {
int fd, status, is_shlib, rv, type;
const char **env;
if ((fd = open(*argv, O_RDONLY, 0)) < 0) {
warn("%s", *argv);
@ -161,12 +197,11 @@ main(int argc, char *argv[])
switch (type) {
case TYPE_ELF:
case TYPE_AOUT:
env = envdef;
break;
#if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED)
case TYPE_ELF32:
env = env32;
break;
rval |= execldd32(*argv, fmt1, fmt2, aflag, vflag);
continue;
#endif
case TYPE_UNKNOWN:
default:
@ -178,15 +213,15 @@ main(int argc, char *argv[])
}
/* ld.so magic */
setenv(env[ENV_OBJECTS], "yes", 1);
setenv(LD_ "TRACE_LOADED_OBJECTS", "yes", 1);
if (fmt1 != NULL)
setenv(env[ENV_OBJECTS_FMT1], fmt1, 1);
setenv(LD_ "TRACE_LOADED_OBJECTS_FMT1", fmt1, 1);
if (fmt2 != NULL)
setenv(env[ENV_OBJECTS_FMT2], fmt2, 1);
setenv(LD_ "TRACE_LOADED_OBJECTS_FMT2", fmt2, 1);
setenv(env[ENV_OBJECTS_PROGNAME], *argv, 1);
setenv(LD_ "TRACE_LOADED_OBJECTS_PROGNAME", *argv, 1);
if (aflag)
setenv(env[ENV_OBJECTS_ALL], "1", 1);
setenv(LD_ "TRACE_LOADED_OBJECTS_ALL", "1", 1);
else if (fmt1 == NULL && fmt2 == NULL)
/* Default formats */
printf("%s:\n", *argv);