summaryrefslogtreecommitdiffstats
path: root/usr.bin/ldd/ldd.c
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2008-08-01 21:52:41 +0000
committerjhb <jhb@FreeBSD.org>2008-08-01 21:52:41 +0000
commita0f546e88ff3ba025ed0bdc1f1bfbcc5b44a1f49 (patch)
tree51f5c7a67159c213618ab3144d35ed1721594f3b /usr.bin/ldd/ldd.c
parent471e3f43d52a6886559e56d484d07d83a871edb4 (diff)
downloadFreeBSD-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/ldd.c')
-rw-r--r--usr.bin/ldd/ldd.c99
1 files changed, 67 insertions, 32 deletions
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);
OpenPOWER on IntegriCloud