ldd.c 7.8 KB

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