ldd.c 6.9 KB

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