diff options
author | jhb <jhb@FreeBSD.org> | 2008-08-01 21:52:41 +0000 |
---|---|---|
committer | jhb <jhb@FreeBSD.org> | 2008-08-01 21:52:41 +0000 |
commit | a0f546e88ff3ba025ed0bdc1f1bfbcc5b44a1f49 (patch) | |
tree | 51f5c7a67159c213618ab3144d35ed1721594f3b /usr.bin/ldd | |
parent | 471e3f43d52a6886559e56d484d07d83a871edb4 (diff) | |
download | FreeBSD-src-a0f546e88ff3ba025ed0bdc1f1bfbcc5b44a1f49.zip FreeBSD-src-a0f546e88ff3ba025ed0bdc1f1bfbcc5b44a1f49.tar.gz |
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)
Diffstat (limited to 'usr.bin/ldd')
-rw-r--r-- | usr.bin/ldd/Makefile | 2 | ||||
-rw-r--r-- | usr.bin/ldd/ldd.1 | 6 | ||||
-rw-r--r-- | usr.bin/ldd/ldd.c | 99 |
3 files changed, 68 insertions, 39 deletions
diff --git a/usr.bin/ldd/Makefile b/usr.bin/ldd/Makefile index bb04f45..357f9f3 100644 --- a/usr.bin/ldd/Makefile +++ b/usr.bin/ldd/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -PROG= ldd +PROG?= ldd SRCS= ldd.c .if ${MACHINE_ARCH} == "i386" SRCS+= sods.c diff --git a/usr.bin/ldd/ldd.1 b/usr.bin/ldd/ldd.1 index fab21eb..72afb39 100644 --- a/usr.bin/ldd/ldd.1 +++ b/usr.bin/ldd/ldd.1 @@ -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 , diff --git a/usr.bin/ldd/ldd.c b/usr.bin/ldd/ldd.c index a130521..53da65e 100644 --- a/usr.bin/ldd/ldd.c +++ b/usr.bin/ldd/ldd.c @@ -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 - -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", -}; +#define _PATH_LDD32 "/usr/bin/ldd32" + +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); |