ldd.c 7.9 KB

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