From 66f269d2a51dae6a2cb10f1a9ae4aaeba815219b Mon Sep 17 00:00:00 2001 From: Eric Andersen Date: Mon, 23 Apr 2001 17:43:54 +0000 Subject: 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 --- ldso/util/ldd.c | 310 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 310 insertions(+) create mode 100644 ldso/util/ldd.c (limited to 'ldso/util/ldd.c') 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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= 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); +} -- cgit v1.2.3