ldd.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. /*
  2. * ldd - print shared library dependencies
  3. *
  4. * usage: ldd [-vVdr] prog ...
  5. * -v: print ldd version
  6. * -V: print ld.so version
  7. * -d: Perform relocations and report any missing functions. (ELF only).
  8. * -r: Perform relocations for both data objects and functions, and
  9. * report any missing objects (ELF only).
  10. * prog ...: programs to check
  11. *
  12. * Copyright 1993-2000, David Engel
  13. *
  14. * This program may be used for any purpose as long as this
  15. * copyright notice is kept.
  16. */
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19. #include <stdarg.h>
  20. #include <string.h>
  21. #include <getopt.h>
  22. #include <unistd.h>
  23. #include <a.out.h>
  24. #include <errno.h>
  25. #include <sys/wait.h>
  26. #include <linux/elf.h>
  27. #include "../config.h"
  28. #include "readelf.h"
  29. #ifdef __GNUC__
  30. void warn(char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
  31. void error(char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
  32. #endif
  33. char *prog = NULL;
  34. void warn(char *fmt, ...)
  35. {
  36. va_list ap;
  37. fflush(stdout); /* don't mix output and error messages */
  38. fprintf(stderr, "%s: warning: ", prog);
  39. va_start(ap, fmt);
  40. vfprintf(stderr, fmt, ap);
  41. va_end(ap);
  42. fprintf(stderr, "\n");
  43. return;
  44. }
  45. void error(char *fmt, ...)
  46. {
  47. va_list ap;
  48. fflush(stdout); /* don't mix output and error messages */
  49. fprintf(stderr, "%s: ", prog);
  50. va_start(ap, fmt);
  51. vfprintf(stderr, fmt, ap);
  52. va_end(ap);
  53. fprintf(stderr, "\n");
  54. exit(1);
  55. }
  56. void *xmalloc(size_t size)
  57. {
  58. void *ptr;
  59. if ((ptr = malloc(size)) == NULL)
  60. error("out of memory");
  61. return ptr;
  62. }
  63. char *xstrdup(char *str)
  64. {
  65. char *ptr;
  66. if ((ptr = strdup(str)) == NULL)
  67. error("out of memory");
  68. return ptr;
  69. }
  70. /* see if prog is a binary file */
  71. int is_bin(char *argv0, char *prog)
  72. {
  73. int res = 0;
  74. FILE *file;
  75. struct exec exec;
  76. char *cp;
  77. int libtype;
  78. /* must be able to open it for reading */
  79. if ((file = fopen(prog, "rb")) == NULL)
  80. fprintf(stderr, "%s: can't open %s (%s)\n", argv0, prog,
  81. strerror(errno));
  82. else
  83. {
  84. /* then see if it's Z, Q or OMAGIC */
  85. if (fread(&exec, sizeof exec, 1, file) < 1)
  86. fprintf(stderr, "%s: can't read header from %s\n", argv0, prog);
  87. else if (N_MAGIC(exec) != ZMAGIC && N_MAGIC(exec) != QMAGIC &&
  88. N_MAGIC(exec) != OMAGIC)
  89. {
  90. struct elfhdr elf_hdr;
  91. rewind(file);
  92. fread(&elf_hdr, sizeof elf_hdr, 1, file);
  93. if (elf_hdr.e_ident[0] != 0x7f ||
  94. strncmp(elf_hdr.e_ident+1, "ELF", 3) != 0)
  95. fprintf(stderr, "%s: %s is not a.out or ELF\n", argv0, prog);
  96. else
  97. {
  98. struct elf_phdr phdr;
  99. int i;
  100. /* Check its an exectuable, library or other */
  101. switch (elf_hdr.e_type)
  102. {
  103. case ET_EXEC:
  104. res = 3;
  105. /* then determine if it is dynamic ELF */
  106. for (i=0; i<elf_hdr.e_phnum; i++)
  107. {
  108. fread(&phdr, sizeof phdr, 1, file);
  109. if (phdr.p_type == PT_DYNAMIC)
  110. {
  111. res = 2;
  112. break;
  113. }
  114. }
  115. break;
  116. case ET_DYN:
  117. if ((cp = readsoname(prog, file, LIB_ANY, &libtype,
  118. elf_hdr.e_ident[EI_CLASS])) != NULL)
  119. free(cp);
  120. if (libtype == LIB_ELF_LIBC5)
  121. res = 5;
  122. else
  123. res = 4;
  124. break;
  125. default:
  126. res = 0;
  127. break;
  128. }
  129. }
  130. }
  131. else
  132. res = 1; /* looks good */
  133. fclose(file);
  134. }
  135. return res;
  136. }
  137. int main(int argc, char **argv, char **envp)
  138. {
  139. int i;
  140. int vprinted = 0;
  141. int resolve = 0;
  142. int bind = 0;
  143. int bintype;
  144. char *ld_preload;
  145. int status = 0;
  146. /* this must be volatile to work with -O, GCC bug? */
  147. volatile loadptr loader = (loadptr)LDSO_ADDR;
  148. prog = argv[0];
  149. while ((i = getopt(argc, argv, "drvV")) != EOF)
  150. switch (i)
  151. {
  152. case 'v':
  153. /* print our version number */
  154. printf("%s: version %s\n", argv[0], VERSION);
  155. vprinted = 1;
  156. break;
  157. case 'd':
  158. bind = 1;
  159. break;
  160. case 'r':
  161. resolve = 1;
  162. break;
  163. case 'V':
  164. /* print the version number of ld.so */
  165. if (uselib(LDSO_IMAGE))
  166. {
  167. fprintf(stderr, "%s: can't load dynamic linker %s (%s)\n",
  168. argv[0], LDSO_IMAGE, strerror(errno));
  169. exit(1);
  170. }
  171. loader(FUNC_VERS, NULL);
  172. vprinted = 1;
  173. break;
  174. }
  175. /* must specify programs if -v or -V not used */
  176. if (optind >= argc && !vprinted)
  177. {
  178. printf("usage: %s [-vVdr] prog ...\n", argv[0]);
  179. exit(0);
  180. }
  181. /* setup the environment for ELF binaries */
  182. putenv("LD_TRACE_LOADED_OBJECTS=1");
  183. if (resolve || bind)
  184. putenv("LD_BIND_NOW=1");
  185. if (resolve)
  186. putenv("LD_WARN=1");
  187. ld_preload = getenv("LD_PRELOAD");
  188. /* print the dependencies for each program */
  189. for (i = optind; i < argc; i++)
  190. {
  191. pid_t pid;
  192. char buff[1024];
  193. /* make sure it's a binary file */
  194. if (!(bintype = is_bin(argv[0], argv[i])))
  195. {
  196. status = 1;
  197. continue;
  198. }
  199. /* print the program name if doing more than one */
  200. if (optind < argc-1)
  201. {
  202. printf("%s:\n", argv[i]);
  203. fflush(stdout);
  204. }
  205. /* no need to fork/exec for static ELF program */
  206. if (bintype == 3)
  207. {
  208. printf("\tstatically linked (ELF)\n");
  209. continue;
  210. }
  211. /* now fork and exec prog with argc = 0 */
  212. if ((pid = fork()) < 0)
  213. {
  214. fprintf(stderr, "%s: can't fork (%s)\n", argv[0], strerror(errno));
  215. exit(1);
  216. }
  217. else if (pid == 0)
  218. {
  219. switch (bintype)
  220. {
  221. case 1: /* a.out */
  222. /* save the name in the enviroment, ld.so may need it */
  223. snprintf(buff, sizeof buff, "%s=%s", LDD_ARGV0, argv[i]);
  224. putenv(buff);
  225. execl(argv[i], NULL);
  226. break;
  227. case 2: /* ELF program */
  228. execl(argv[i], argv[i], NULL);
  229. break;
  230. case 4: /* ELF libc6 library */
  231. /* try to use /lib/ld-linux.so.2 first */
  232. #if !defined(__mc68000__)
  233. execl("/lib/ld-linux.so.2", "/lib/ld-linux.so.2",
  234. "--list", argv[i], NULL);
  235. #else
  236. execl("/lib/ld.so.1", "/lib/ld.so.1",
  237. "--list", argv[i], NULL);
  238. #endif
  239. /* fall through */
  240. case 5: /* ELF libc5 library */
  241. /* if that fails, add library to LD_PRELOAD and
  242. then execute lddstub */
  243. if (ld_preload && *ld_preload)
  244. snprintf(buff, sizeof buff, "LD_PRELOAD=%s:%s%s",
  245. ld_preload, *argv[i] == '/' ? "" : "./", argv[i]);
  246. else
  247. snprintf(buff, sizeof buff, "LD_PRELOAD=%s%s",
  248. *argv[i] == '/' ? "" : "./", argv[i]);
  249. putenv(buff);
  250. execl(LDDSTUB, argv[i], NULL);
  251. break;
  252. default:
  253. fprintf(stderr, "%s: internal error, bintype = %d\n",
  254. argv[0], bintype);
  255. exit(1);
  256. }
  257. fprintf(stderr, "%s: can't execute %s (%s)\n", argv[0], argv[i],
  258. strerror(errno));
  259. exit(1);
  260. }
  261. else
  262. {
  263. /* then wait for it to complete */
  264. int status;
  265. if (waitpid(pid, &status, 0) != pid)
  266. {
  267. fprintf(stderr, "%s: error waiting for %s (%s)\n", argv[0],
  268. argv[i], strerror(errno));
  269. }
  270. else if (WIFSIGNALED(status))
  271. {
  272. fprintf(stderr, "%s: %s exited with signal %d\n", argv[0],
  273. argv[i], WTERMSIG(status));
  274. }
  275. }
  276. }
  277. exit(status);
  278. }