Logo Search packages:      
Sourcecode: ld.so version File versions

ldd.c

/*
 * 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);
}

Generated by  Doxygen 1.6.0   Back to index