123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340 |
- /*
- * 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 <errno.h>
- #include <sys/wait.h>
- #include "../d-link/elf.h"
- #include "../config.h"
- #include "readelf.h"
- struct exec
- {
- unsigned long a_info; /* Use macros N_MAGIC, etc for access */
- unsigned a_text; /* length of text, in bytes */
- unsigned a_data; /* length of data, in bytes */
- unsigned a_bss; /* length of uninitialized data area for file, in bytes */
- unsigned a_syms; /* length of symbol table data in file, in bytes */
- unsigned a_entry; /* start address */
- unsigned a_trsize; /* length of relocation info for text, in bytes */
- unsigned a_drsize; /* length of relocation info for data, in bytes */
- };
- #if !defined (N_MAGIC)
- #define N_MAGIC(exec) ((exec).a_info & 0xffff)
- #endif
- /* Code indicating object file or impure executable. */
- #define OMAGIC 0407
- /* Code indicating pure executable. */
- #define NMAGIC 0410
- /* Code indicating demand-paged executable. */
- #define ZMAGIC 0413
- /* This indicates a demand-paged executable with the header in the text.
- The first page is unmapped to help trap NULL pointer references */
- #define QMAGIC 0314
- /* Code indicating core file. */
- #define CMAGIC 0421
- extern int uselib(const char *library);
- #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)
- {
- 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
- {
- 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);
- }
|