summaryrefslogtreecommitdiff
path: root/ldso/util/ldd.c
diff options
context:
space:
mode:
authorEric Andersen <andersen@codepoet.org>2001-04-23 17:43:54 +0000
committerEric Andersen <andersen@codepoet.org>2001-04-23 17:43:54 +0000
commit66f269d2a51dae6a2cb10f1a9ae4aaeba815219b (patch)
treee2094832990caf6d849ba90e4b1a82a6264f86b3 /ldso/util/ldd.c
parentc4a3f3f81ea90e3df93c352ac0e2161a4bfd3327 (diff)
Initial checkin for ld.so. This is a combination of effort from Manuel Novoa
III and me. I've been working on stripping out arch dependant stuff and replacing it with generic stuff whenever possible. -Erik
Diffstat (limited to 'ldso/util/ldd.c')
-rw-r--r--ldso/util/ldd.c310
1 files changed, 310 insertions, 0 deletions
diff --git a/ldso/util/ldd.c b/ldso/util/ldd.c
new file mode 100644
index 000000000..62c479ba3
--- /dev/null
+++ b/ldso/util/ldd.c
@@ -0,0 +1,310 @@
+/*
+ * ldd - print shared library dependencies
+ *
+ * usage: ldd [-vVdr] prog ...
+ * -v: print ldd version
+ * -V: print ld.so version
+ * -d: Perform relocations and report any missing functions. (ELF only).
+ * -r: Perform relocations for both data objects and functions, and
+ * report any missing objects (ELF only).
+ * prog ...: programs to check
+ *
+ * Copyright 1993-2000, David Engel
+ *
+ * This program may be used for any purpose as long as this
+ * copyright notice is kept.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <getopt.h>
+#include <unistd.h>
+#include <a.out.h>
+#include <errno.h>
+#include <sys/wait.h>
+#include <linux/elf.h>
+#include "../config.h"
+#include "readelf.h"
+
+#ifdef __GNUC__
+void warn(char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
+void error(char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
+#endif
+
+char *prog = NULL;
+
+void warn(char *fmt, ...)
+{
+ va_list ap;
+
+ fflush(stdout); /* don't mix output and error messages */
+ fprintf(stderr, "%s: warning: ", prog);
+
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+
+ fprintf(stderr, "\n");
+
+ return;
+}
+
+void error(char *fmt, ...)
+{
+ va_list ap;
+
+ fflush(stdout); /* don't mix output and error messages */
+ fprintf(stderr, "%s: ", prog);
+
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+
+ fprintf(stderr, "\n");
+
+ exit(1);
+}
+
+void *xmalloc(size_t size)
+{
+ void *ptr;
+ if ((ptr = malloc(size)) == NULL)
+ error("out of memory");
+ return ptr;
+}
+
+char *xstrdup(char *str)
+{
+ char *ptr;
+ if ((ptr = strdup(str)) == NULL)
+ error("out of memory");
+ return ptr;
+}
+
+/* see if prog is a binary file */
+int is_bin(char *argv0, char *prog)
+{
+ int res = 0;
+ FILE *file;
+ struct exec exec;
+ char *cp;
+ int libtype;
+
+ /* must be able to open it for reading */
+ if ((file = fopen(prog, "rb")) == NULL)
+ fprintf(stderr, "%s: can't open %s (%s)\n", argv0, prog,
+ strerror(errno));
+ else
+ {
+ /* then see if it's Z, Q or OMAGIC */
+ if (fread(&exec, sizeof exec, 1, file) < 1)
+ fprintf(stderr, "%s: can't read header from %s\n", argv0, prog);
+ else if (N_MAGIC(exec) != ZMAGIC && N_MAGIC(exec) != QMAGIC &&
+ N_MAGIC(exec) != OMAGIC)
+ {
+ struct elfhdr elf_hdr;
+
+ rewind(file);
+ fread(&elf_hdr, sizeof elf_hdr, 1, file);
+ if (elf_hdr.e_ident[0] != 0x7f ||
+ strncmp(elf_hdr.e_ident+1, "ELF", 3) != 0)
+ fprintf(stderr, "%s: %s is not a.out or ELF\n", argv0, prog);
+ else
+ {
+ struct elf_phdr phdr;
+ int i;
+
+ /* Check its an exectuable, library or other */
+ switch (elf_hdr.e_type)
+ {
+ case ET_EXEC:
+ res = 3;
+ /* then determine if it is dynamic ELF */
+ for (i=0; i<elf_hdr.e_phnum; i++)
+ {
+ fread(&phdr, sizeof phdr, 1, file);
+ if (phdr.p_type == PT_DYNAMIC)
+ {
+ res = 2;
+ break;
+ }
+ }
+ break;
+ case ET_DYN:
+ if ((cp = readsoname(prog, file, LIB_ANY, &libtype,
+ elf_hdr.e_ident[EI_CLASS])) != NULL)
+ free(cp);
+ if (libtype == LIB_ELF_LIBC5)
+ res = 5;
+ else
+ res = 4;
+ break;
+ default:
+ res = 0;
+ break;
+ }
+ }
+ }
+ else
+ res = 1; /* looks good */
+
+ fclose(file);
+ }
+ return res;
+}
+
+int main(int argc, char **argv, char **envp)
+{
+ int i;
+ int vprinted = 0;
+ int resolve = 0;
+ int bind = 0;
+ int bintype;
+ char *ld_preload;
+ int status = 0;
+
+ /* this must be volatile to work with -O, GCC bug? */
+ volatile loadptr loader = (loadptr)LDSO_ADDR;
+
+ prog = argv[0];
+
+ while ((i = getopt(argc, argv, "drvV")) != EOF)
+ switch (i)
+ {
+ case 'v':
+ /* print our version number */
+ printf("%s: version %s\n", argv[0], VERSION);
+ vprinted = 1;
+ break;
+ case 'd':
+ bind = 1;
+ break;
+ case 'r':
+ resolve = 1;
+ break;
+ case 'V':
+ /* print the version number of ld.so */
+ if (uselib(LDSO_IMAGE))
+ {
+ fprintf(stderr, "%s: can't load dynamic linker %s (%s)\n",
+ argv[0], LDSO_IMAGE, strerror(errno));
+ exit(1);
+ }
+ loader(FUNC_VERS, NULL);
+ vprinted = 1;
+ break;
+ }
+
+ /* must specify programs if -v or -V not used */
+ if (optind >= argc && !vprinted)
+ {
+ printf("usage: %s [-vVdr] prog ...\n", argv[0]);
+ exit(0);
+ }
+
+ /* setup the environment for ELF binaries */
+ putenv("LD_TRACE_LOADED_OBJECTS=1");
+ if (resolve || bind)
+ putenv("LD_BIND_NOW=1");
+ if (resolve)
+ putenv("LD_WARN=1");
+ ld_preload = getenv("LD_PRELOAD");
+
+ /* print the dependencies for each program */
+ for (i = optind; i < argc; i++)
+ {
+ pid_t pid;
+ char buff[1024];
+
+ /* make sure it's a binary file */
+ if (!(bintype = is_bin(argv[0], argv[i])))
+ {
+ status = 1;
+ continue;
+ }
+
+ /* print the program name if doing more than one */
+ if (optind < argc-1)
+ {
+ printf("%s:\n", argv[i]);
+ fflush(stdout);
+ }
+
+ /* no need to fork/exec for static ELF program */
+ if (bintype == 3)
+ {
+ printf("\tstatically linked (ELF)\n");
+ continue;
+ }
+
+ /* now fork and exec prog with argc = 0 */
+ if ((pid = fork()) < 0)
+ {
+ fprintf(stderr, "%s: can't fork (%s)\n", argv[0], strerror(errno));
+ exit(1);
+ }
+ else if (pid == 0)
+ {
+ switch (bintype)
+ {
+ case 1: /* a.out */
+ /* save the name in the enviroment, ld.so may need it */
+ snprintf(buff, sizeof buff, "%s=%s", LDD_ARGV0, argv[i]);
+ putenv(buff);
+ execl(argv[i], NULL);
+ break;
+ case 2: /* ELF program */
+ execl(argv[i], argv[i], NULL);
+ break;
+ case 4: /* ELF libc6 library */
+ /* try to use /lib/ld-linux.so.2 first */
+#if !defined(__mc68000__)
+ execl("/lib/ld-linux.so.2", "/lib/ld-linux.so.2",
+ "--list", argv[i], NULL);
+#else
+ execl("/lib/ld.so.1", "/lib/ld.so.1",
+ "--list", argv[i], NULL);
+#endif
+ /* fall through */
+ case 5: /* ELF libc5 library */
+ /* if that fails, add library to LD_PRELOAD and
+ then execute lddstub */
+ if (ld_preload && *ld_preload)
+ snprintf(buff, sizeof buff, "LD_PRELOAD=%s:%s%s",
+ ld_preload, *argv[i] == '/' ? "" : "./", argv[i]);
+ else
+ snprintf(buff, sizeof buff, "LD_PRELOAD=%s%s",
+ *argv[i] == '/' ? "" : "./", argv[i]);
+ putenv(buff);
+ execl(LDDSTUB, argv[i], NULL);
+ break;
+ default:
+ fprintf(stderr, "%s: internal error, bintype = %d\n",
+ argv[0], bintype);
+ exit(1);
+ }
+ fprintf(stderr, "%s: can't execute %s (%s)\n", argv[0], argv[i],
+ strerror(errno));
+ exit(1);
+ }
+ else
+ {
+ /* then wait for it to complete */
+ int status;
+ if (waitpid(pid, &status, 0) != pid)
+ {
+ fprintf(stderr, "%s: error waiting for %s (%s)\n", argv[0],
+ argv[i], strerror(errno));
+ }
+ else if (WIFSIGNALED(status))
+ {
+ fprintf(stderr, "%s: %s exited with signal %d\n", argv[0],
+ argv[i], WTERMSIG(status));
+ }
+ }
+ }
+
+ exit(status);
+}