OSDN Git Service

add __thumb__ check
[uclinux-h8/uClibc.git] / utils / ldd.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * A small little ldd implementation for uClibc
4  *
5  * Copyright (C) 2000-2004 Erik Andersen <andersee@debian.org>
6  *
7  * Several functions in this file (specifically, elf_find_section_type(),
8  * elf_find_phdr_type(), and elf_find_dynamic(), were stolen from elflib.c from
9  * elfvector (http://www.BitWagon.com/elfvector.html) by John F. Reiser
10  * <jreiser@BitWagon.com>, which is copyright 2000 BitWagon Software LLC
11  * (GPL2).
12  *
13  * This program is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 2 of the License, or
16  * (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21  * General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26  *
27  */
28
29
30 #define _GNU_SOURCE
31 #include <stdlib.h>
32 #include <stdio.h>
33 #include <fcntl.h>
34 #include <string.h>
35 #include <unistd.h>
36 #include <sys/mman.h>
37 #include <sys/stat.h>
38 #include <sys/types.h>
39 #include <sys/types.h>
40 #include <sys/wait.h>
41
42 #include "bswap.h"
43 #if defined (sun)
44 #include "link.h"
45 #else
46 #include "elf.h"
47 #endif
48 #include "dl-defs.h"
49
50 #ifdef DMALLOC
51 #include <dmalloc.h>
52 #endif
53
54 #if defined(__arm__) || defined(__thumb__)
55 #define MATCH_MACHINE(x) (x == EM_ARM)
56 #define ELFCLASSM       ELFCLASS32
57 #endif
58
59 #if defined(__s390__)
60 #define MATCH_MACHINE(x) (x == EM_S390)
61 #define ELFCLASSM       ELFCLASS32
62 #endif
63
64 #if defined(__i386__)
65 #ifndef EM_486
66 #define MATCH_MACHINE(x) (x == EM_386)
67 #else
68 #define MATCH_MACHINE(x) (x == EM_386 || x == EM_486)
69 #endif
70 #define ELFCLASSM       ELFCLASS32
71 #endif
72
73 #if defined(__mc68000__)
74 #define MATCH_MACHINE(x) (x == EM_68K)
75 #define ELFCLASSM       ELFCLASS32
76 #endif
77
78 #if defined(__mips__)
79 #define MATCH_MACHINE(x) (x == EM_MIPS || x == EM_MIPS_RS3_LE)
80 #define ELFCLASSM       ELFCLASS32
81 #endif
82
83 #if defined(__powerpc__)
84 #define MATCH_MACHINE(x) (x == EM_PPC)
85 #define ELFCLASSM       ELFCLASS32
86 #endif
87
88 #if defined(__sh__)
89 #define MATCH_MACHINE(x) (x == EM_SH)
90 #define ELFCLASSM       ELFCLASS32
91 #endif
92
93 #if defined (__v850e__)
94 #define MATCH_MACHINE(x) ((x) == EM_V850 || (x) == EM_CYGNUS_V850)
95 #define ELFCLASSM       ELFCLASS32
96 #endif
97
98 #if defined (__sparc__)
99 #define MATCH_MACHINE(x) ((x) == EM_SPARC || (x) == EM_SPARC32PLUS)
100 #define ELFCLASSM    ELFCLASS32
101 #endif
102
103 #if defined(__cris__)
104 #define MATCH_MACHINE(x) (x == EM_CRIS)
105 #define ELFCLASSM       ELFCLASS32
106 #endif
107
108 #ifndef MATCH_MACHINE
109 #warning "You really should add a MATCH_MACHINE() macro for your architecture"
110 #endif
111
112 #if __BYTE_ORDER == __LITTLE_ENDIAN
113 #define ELFDATAM        ELFDATA2LSB
114 #elif __BYTE_ORDER == __BIG_ENDIAN
115 #define ELFDATAM        ELFDATA2MSB
116 #endif
117
118 struct library {
119         char *name;
120         int resolved;
121         char *path;
122         struct library *next;
123 };
124 struct library *lib_list = NULL;
125 char not_found[] = "not found";
126 char *interp = NULL;
127 char *interp_dir = NULL;
128 int byteswap;
129 static int interpreter_already_found=0;
130
131 inline uint32_t byteswap32_to_host(uint32_t value)
132 {
133         if (byteswap==1) {
134                 return(bswap_32(value));
135         } else {
136                 return(value);
137         }
138 }
139
140 Elf32_Shdr * elf_find_section_type( int key, Elf32_Ehdr *ehdr)
141 {
142         int j;
143         Elf32_Shdr *shdr;
144         shdr = (Elf32_Shdr *)(ehdr->e_shoff + (char *)ehdr);
145         for (j = ehdr->e_shnum; --j>=0; ++shdr) {
146                 if (key==(int)byteswap32_to_host(shdr->sh_type)) {
147                         return shdr;
148                 }
149         }
150         return NULL;
151 }
152
153 Elf32_Phdr * elf_find_phdr_type( int type, Elf32_Ehdr *ehdr)
154 {
155         int j;
156         Elf32_Phdr *phdr = (Elf32_Phdr *)(ehdr->e_phoff + (char *)ehdr);
157         for (j = ehdr->e_phnum; --j>=0; ++phdr) {
158                 if (type==(int)byteswap32_to_host(phdr->p_type)) {
159                         return phdr;
160                 }
161         }
162         return NULL;
163 }
164
165 /* Returns value if return_val==1, ptr otherwise */
166 void * elf_find_dynamic(int const key, Elf32_Dyn *dynp,
167         Elf32_Ehdr *ehdr, int return_val)
168 {
169         Elf32_Phdr *pt_text = elf_find_phdr_type(PT_LOAD, ehdr);
170         unsigned tx_reloc = byteswap32_to_host(pt_text->p_vaddr) - byteswap32_to_host(pt_text->p_offset);
171         for (; DT_NULL!=byteswap32_to_host(dynp->d_tag); ++dynp) {
172                 if (key == (int)byteswap32_to_host(dynp->d_tag)) {
173                         if (return_val == 1)
174                                 return (void *)(intptr_t)byteswap32_to_host(dynp->d_un.d_val);
175                         else
176                                 return (void *)(byteswap32_to_host(dynp->d_un.d_val) - tx_reloc + (char *)ehdr );
177                 }
178         }
179         return NULL;
180 }
181
182 static char * elf_find_rpath(Elf32_Ehdr* ehdr, Elf32_Dyn* dynamic)
183 {
184         Elf32_Dyn  *dyns;
185
186         for (dyns=dynamic; byteswap32_to_host(dyns->d_tag)!=DT_NULL; ++dyns) {
187                 if (DT_RPATH == byteswap32_to_host(dyns->d_tag)) {
188                         char *strtab;
189                         strtab = (char *)elf_find_dynamic(DT_STRTAB, dynamic, ehdr, 0);
190                         return ((char*)strtab + byteswap32_to_host(dyns->d_un.d_val));
191                 }
192         }
193         return NULL;
194 }
195
196 int check_elf_header(Elf32_Ehdr *const ehdr)
197 {
198         if (! ehdr || strncmp((void *)ehdr, ELFMAG, SELFMAG) != 0 ||
199                         ehdr->e_ident[EI_CLASS] != ELFCLASS32 ||
200                         ehdr->e_ident[EI_VERSION] != EV_CURRENT)
201         {
202                 return 1;
203         }
204
205         /* Check if the target endianness matches the host's endianness */
206         byteswap = 0;
207 #if __BYTE_ORDER == __LITTLE_ENDIAN
208         if (ehdr->e_ident[5] == ELFDATA2MSB) {
209                 /* Ick -- we will have to byte-swap everything */
210                 byteswap = 1;
211         }
212 #elif __BYTE_ORDER == __BIG_ENDIAN
213         if (ehdr->e_ident[5] == ELFDATA2LSB) {
214                 /* Ick -- we will have to byte-swap everything */
215                 byteswap = 1;
216         }
217 #else
218 #error Unknown host byte order!
219 #endif
220
221         /* Be vary lazy, and only byteswap the stuff we use */
222         if (byteswap==1) {
223                 ehdr->e_type=bswap_16(ehdr->e_type);
224                 ehdr->e_phoff=bswap_32(ehdr->e_phoff);
225                 ehdr->e_shoff=bswap_32(ehdr->e_shoff);
226                 ehdr->e_phnum=bswap_16(ehdr->e_phnum);
227                 ehdr->e_shnum=bswap_16(ehdr->e_shnum);
228         }
229
230         return 0;
231 }
232
233 #ifdef __LDSO_CACHE_SUPPORT__
234 static caddr_t cache_addr = NULL;
235 static size_t cache_size = 0;
236
237 int map_cache(void)
238 {
239         int fd;
240         struct stat st;
241         header_t *header;
242         libentry_t *libent;
243         int i, strtabsize;
244
245         if (cache_addr == (caddr_t) - 1)
246                 return -1;
247         else if (cache_addr != NULL)
248                 return 0;
249
250         if (stat(LDSO_CACHE, &st)
251                         || (fd = open(LDSO_CACHE, O_RDONLY, 0)) < 0) {
252                 dprintf(2, "ldd: can't open cache '%s'\n", LDSO_CACHE);
253                 cache_addr = (caddr_t) - 1;     /* so we won't try again */
254                 return -1;
255         }
256
257         cache_size = st.st_size;
258         cache_addr = (caddr_t) mmap(0, cache_size, PROT_READ, MAP_SHARED, fd, 0);
259         close(fd);
260         if (cache_addr == MAP_FAILED) {
261                 dprintf(2, "ldd: can't map cache '%s'\n", LDSO_CACHE);
262                 return -1;
263         }
264
265         header = (header_t *) cache_addr;
266
267         if (cache_size < sizeof(header_t) ||
268                         memcmp(header->magic, LDSO_CACHE_MAGIC, LDSO_CACHE_MAGIC_LEN)
269                         || memcmp(header->version, LDSO_CACHE_VER, LDSO_CACHE_VER_LEN)
270                         || cache_size <
271                         (sizeof(header_t) + header->nlibs * sizeof(libentry_t))
272                         || cache_addr[cache_size - 1] != '\0')
273         {
274                 dprintf(2, "ldd: cache '%s' is corrupt\n", LDSO_CACHE);
275                 goto fail;
276         }
277
278         strtabsize = cache_size - sizeof(header_t) -
279                 header->nlibs * sizeof(libentry_t);
280         libent = (libentry_t *) & header[1];
281
282         for (i = 0; i < header->nlibs; i++) {
283                 if (libent[i].sooffset >= strtabsize ||
284                                 libent[i].liboffset >= strtabsize)
285                 {
286                         dprintf(2, "ldd: cache '%s' is corrupt\n", LDSO_CACHE);
287                         goto fail;
288                 }
289         }
290
291         return 0;
292
293 fail:
294         munmap(cache_addr, cache_size);
295         cache_addr = (caddr_t) - 1;
296         return -1;
297 }
298
299 int unmap_cache(void)
300 {
301         if (cache_addr == NULL || cache_addr == (caddr_t) - 1)
302                 return -1;
303
304 #if 1
305         munmap(cache_addr, cache_size);
306         cache_addr = NULL;
307 #endif
308
309         return 0;
310 }
311 #else
312 static inline void map_cache(void) { }
313 static inline void unmap_cache(void) { }
314 #endif
315
316 /* This function's behavior must exactly match that
317  * in uClibc/ldso/ldso/dl-elf.c */
318 static void search_for_named_library(char *name, char *result, const char *path_list)
319 {
320         int i, count = 1;
321         char *path, *path_n;
322         struct stat filestat;
323
324         /* We need a writable copy of this string */
325         path = strdup(path_list);
326         if (!path) {
327                 fprintf(stderr, "Out of memory!\n");
328                 exit(EXIT_FAILURE);
329         }
330         /* Eliminate all double //s */
331         path_n=path;
332         while((path_n=strstr(path_n, "//"))) {
333                 i = strlen(path_n);
334                 memmove(path_n, path_n+1, i-1);
335                 *(path_n + i - 1)='\0';
336         }
337
338         /* Replace colons with zeros in path_list and count them */
339         for(i=strlen(path); i > 0; i--) {
340                 if (path[i]==':') {
341                         path[i]=0;
342                         count++;
343                 }
344         }
345         path_n = path;
346         for (i = 0; i < count; i++) {
347                 strcpy(result, path_n);
348                 strcat(result, "/");
349                 strcat(result, name);
350                 if (stat (result, &filestat) == 0 && filestat.st_mode & S_IRUSR) {
351                         free(path);
352                         return;
353                 }
354                 path_n += (strlen(path_n) + 1);
355         }
356         free(path);
357         *result = '\0';
358 }
359
360 void locate_library_file(Elf32_Ehdr* ehdr, Elf32_Dyn* dynamic, int is_suid, struct library *lib)
361 {
362         char *buf;
363         char *path;
364         struct stat filestat;
365
366         /* If this is a fully resolved name, our job is easy */
367         if (stat (lib->name, &filestat) == 0) {
368                 lib->path = strdup(lib->name);
369                 return;
370         }
371
372         /* We need some elbow room here.  Make some room...*/
373         buf = malloc(1024);
374         if (!buf) {
375                 fprintf(stderr, "Out of memory!\n");
376                 exit(EXIT_FAILURE);
377         }
378
379         /* This function must match the behavior of _dl_load_shared_library
380          * in readelflib1.c or things won't work out as expected... */
381
382         /* The ABI specifies that RPATH is searched first, so do that now.  */
383         path = elf_find_rpath(ehdr, dynamic);
384         if (path) {
385                 search_for_named_library(lib->name, buf, path);
386                 if (*buf != '\0') {
387                         lib->path = buf;
388                         return;
389                 }
390         }
391
392         /* Next check LD_{ELF_}LIBRARY_PATH if specified and allowed.
393          * Since this app doesn't actually run an executable I will skip
394          * the suid check, and just use LD_{ELF_}LIBRARY_PATH if set */
395         if (is_suid==1)
396                 path = NULL;
397         else
398                 path = getenv("LD_LIBRARY_PATH");
399         if (path) {
400                 search_for_named_library(lib->name, buf, path);
401                 if (*buf != '\0') {
402                         lib->path = buf;
403                         return;
404                 }
405         }
406
407 #ifdef __LDSO_CACHE_SUPPORT__
408         if (cache_addr != NULL && cache_addr != (caddr_t) - 1) {
409                 int i;
410                 header_t *header = (header_t *) cache_addr;
411                 libentry_t *libent = (libentry_t *) & header[1];
412                 char *strs = (char *) &libent[header->nlibs];
413
414                 for (i = 0; i < header->nlibs; i++) {
415                         if ((libent[i].flags == LIB_ELF ||
416                             libent[i].flags == LIB_ELF_LIBC0 ||
417                             libent[i].flags == LIB_ELF_LIBC5) &&
418                             strcmp(lib->name, strs + libent[i].sooffset) == 0) {
419                                 lib->path = strdup(strs + libent[i].liboffset);
420                                 return;
421                         }
422                 }
423         }
424 #endif
425
426
427         /* Next look for libraries wherever the shared library
428          * loader was installed -- this is usually where we
429          * should find things... */
430         if (interp_dir) {
431                 search_for_named_library(lib->name, buf, interp_dir);
432                 if (*buf != '\0') {
433                         lib->path = buf;
434                         return;
435                 }
436         }
437
438         /* Lastly, search the standard list of paths for the library.
439            This list must exactly match the list in uClibc/ldso/ldso/dl-elf.c */
440         path =  UCLIBC_RUNTIME_PREFIX "lib:"
441                 UCLIBC_RUNTIME_PREFIX "usr/lib"
442 #ifndef __LDSO_CACHE_SUPPORT__
443                 ":" UCLIBC_RUNTIME_PREFIX "usr/X11R6/lib"
444 #endif
445                 ;
446         search_for_named_library(lib->name, buf, path);
447         if (*buf != '\0') {
448                 lib->path = buf;
449         } else {
450                 free(buf);
451                 lib->path = not_found;
452         }
453 }
454
455 static int add_library(Elf32_Ehdr* ehdr, Elf32_Dyn* dynamic, int is_setuid, char *s)
456 {
457         char *tmp, *tmp1, *tmp2;
458         struct library *cur, *newlib=lib_list;
459
460         if (!s || !strlen(s))
461                 return 1;
462
463         tmp = s;
464         while (*tmp) {
465                 if (*tmp == '/')
466                         s = tmp + 1;
467                 tmp++;
468         }
469
470         /* We add ldso elsewhere */
471         if (interpreter_already_found && (tmp=strrchr(interp, '/')) != NULL)
472         {
473                 int len = strlen(interp_dir);
474                 if (strcmp(s, interp+1+len)==0)
475                         return 1;
476         }
477
478         for (cur = lib_list; cur; cur=cur->next) {
479                 /* Check if this library is already in the list */
480                 tmp1 = tmp2 = cur->name;
481                 while (*tmp1) {
482                         if (*tmp1 == '/')
483                                 tmp2 = tmp1 + 1;
484                         tmp1++;
485                 }
486                 if(strcmp(tmp2, s)==0) {
487                         //printf("find_elf_interpreter is skipping '%s' (already in list)\n", cur->name);
488                         return 0;
489                 }
490         }
491
492         /* Ok, this lib needs to be added to the list */
493         newlib = malloc(sizeof(struct library));
494         if (!newlib)
495                 return 1;
496         newlib->name = malloc(strlen(s)+1);
497         strcpy(newlib->name, s);
498         newlib->resolved = 0;
499         newlib->path = NULL;
500         newlib->next = NULL;
501
502         /* Now try and locate where this library might be living... */
503         locate_library_file(ehdr, dynamic, is_setuid, newlib);
504
505         //printf("add_library is adding '%s' to '%s'\n", newlib->name, newlib->path);
506         if (!lib_list) {
507                 lib_list = newlib;
508         } else {
509                 for (cur = lib_list;  cur->next; cur=cur->next); /* nothing */
510                 cur->next = newlib;
511         }
512         return 0;
513 }
514
515 static void find_needed_libraries(Elf32_Ehdr* ehdr,
516                 Elf32_Dyn* dynamic, int is_setuid)
517 {
518         Elf32_Dyn  *dyns;
519
520         for (dyns=dynamic; byteswap32_to_host(dyns->d_tag)!=DT_NULL; ++dyns) {
521                 if (DT_NEEDED == byteswap32_to_host(dyns->d_tag)) {
522                         char *strtab;
523                         strtab = (char *)elf_find_dynamic(DT_STRTAB, dynamic, ehdr, 0);
524                         add_library(ehdr, dynamic, is_setuid,
525                                         (char*)strtab + byteswap32_to_host(dyns->d_un.d_val));
526                 }
527         }
528 }
529
530 static struct library * find_elf_interpreter(Elf32_Ehdr* ehdr)
531 {
532         Elf32_Phdr *phdr;
533
534         if (interpreter_already_found==1)
535                 return NULL;
536         phdr = elf_find_phdr_type(PT_INTERP, ehdr);
537         if (phdr) {
538                 struct library *cur, *newlib=NULL;
539                 char *s = (char*)ehdr + byteswap32_to_host(phdr->p_offset);
540
541                 char *tmp, *tmp1;
542                 interp = strdup(s);
543                 interp_dir = strdup(s);
544                 tmp = strrchr(interp_dir, '/');
545                 if (*tmp)
546                         *tmp = '\0';
547                 else {
548                         free(interp_dir);
549                         interp_dir = interp;
550                 }
551                 tmp1 = tmp = s;
552                 while (*tmp) {
553                         if (*tmp == '/')
554                                 tmp1 = tmp + 1;
555                         tmp++;
556                 }
557                 for (cur = lib_list; cur; cur=cur->next) {
558                         /* Check if this library is already in the list */
559                         if(strcmp(cur->name, tmp1)==0) {
560                                 //printf("find_elf_interpreter is replacing '%s' (already in list)\n", cur->name);
561                                 newlib = cur;
562                                 free(newlib->name);
563                                 if (newlib->path != not_found) {
564                                         free(newlib->path);
565                                 }
566                                 newlib->name = NULL;
567                                 newlib->path = NULL;
568                                 return NULL;
569                         }
570                 }
571                 if (newlib == NULL)
572                         newlib = malloc(sizeof(struct library));
573                 if (!newlib)
574                         return NULL;
575                 newlib->name = malloc(strlen(s)+1);
576                 strcpy(newlib->name, s);
577                 newlib->path = strdup(newlib->name);
578                 newlib->resolved = 1;
579                 newlib->next = NULL;
580
581 #if 0
582                 //printf("find_elf_interpreter is adding '%s' to '%s'\n", newlib->name, newlib->path);
583                 if (!lib_list) {
584                         lib_list = newlib;
585                 } else {
586                         for (cur = lib_list;  cur->next; cur=cur->next); /* nothing */
587                         cur->next = newlib;
588                 }
589 #endif
590                 interpreter_already_found=1;
591                 return newlib;
592         }
593         return NULL;
594 }
595
596 /* map the .so, and locate interesting pieces */
597 int find_dependancies(char* filename)
598 {
599         int is_suid = 0;
600         FILE *thefile;
601         struct stat statbuf;
602         Elf32_Ehdr *ehdr = NULL;
603         Elf32_Shdr *dynsec = NULL;
604         Elf32_Dyn *dynamic = NULL;
605         struct library *interp;
606
607         if (filename == not_found)
608                 return 0;
609
610         if (!filename) {
611                 fprintf(stderr, "No filename specified.\n");
612                 return -1;
613         }
614         if (!(thefile = fopen(filename, "r"))) {
615                 perror(filename);
616                 return -1;
617         }
618         if (fstat(fileno(thefile), &statbuf) < 0) {
619                 perror(filename);
620                 fclose(thefile);
621                 return -1;
622         }
623
624         if ((size_t)statbuf.st_size < sizeof(Elf32_Ehdr))
625                 goto foo;
626
627         if (!S_ISREG(statbuf.st_mode))
628                 goto foo;
629
630         /* mmap the file to make reading stuff from it effortless */
631         ehdr = (Elf32_Ehdr *)mmap(0, statbuf.st_size,
632                         PROT_READ|PROT_WRITE, MAP_PRIVATE, fileno(thefile), 0);
633         if (ehdr == MAP_FAILED) {
634                 fclose(thefile);
635                 fprintf(stderr, "Out of memory!\n");
636                 return -1;
637         }
638
639 foo:
640         fclose(thefile);
641
642         /* Check if this looks like a legit ELF file */
643         if (check_elf_header(ehdr)) {
644                 fprintf(stderr, "%s: not an ELF file.\n", filename);
645                 return -1;
646         }
647         /* Check if this is the right kind of ELF file */
648         if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN) {
649                 fprintf(stderr, "%s: not a dynamic executable\n", filename);
650                 return -1;
651         }
652         if (ehdr->e_type == ET_EXEC || ehdr->e_type == ET_DYN) {
653                 if (statbuf.st_mode & S_ISUID)
654                         is_suid = 1;
655                 if ((statbuf.st_mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP))
656                         is_suid = 1;
657                 /* FIXME */
658                 if (is_suid)
659                         fprintf(stderr, "%s: is setuid\n", filename);
660         }
661
662         interpreter_already_found=0;
663         interp = find_elf_interpreter(ehdr);
664
665 #ifdef __LDSO_LDD_SUPPORT__
666         if (interp && (ehdr->e_type == ET_EXEC || ehdr->e_type == ET_DYN) && ehdr->e_ident[EI_CLASS] == ELFCLASSM &&
667                         ehdr->e_ident[EI_DATA] == ELFDATAM
668                         && ehdr->e_ident[EI_VERSION] == EV_CURRENT && MATCH_MACHINE(ehdr->e_machine))
669         {
670                 struct stat statbuf;
671                 if (stat(interp->path, &statbuf) == 0 && S_ISREG(statbuf.st_mode)) {
672                         pid_t pid;
673                         int status;
674                         static const char * const environment[] = {
675                                 "PATH=/usr/bin:/bin:/usr/sbin:/sbin",
676                                 "SHELL=/bin/sh",
677                                 "LD_TRACE_LOADED_OBJECTS=1",
678                                 NULL
679                         };
680
681                         if ((pid = fork()) == 0) {
682                                 /* Cool, it looks like we should be able to actually
683                                  * run this puppy.  Do so now... */
684                                 execle(filename, filename, NULL, environment);
685                                 _exit(0xdead);
686                         }
687
688                         /* Wait till it returns */
689                         waitpid(pid, &status, 0);
690                         if (WIFEXITED(status) && WEXITSTATUS(status)==0) {
691                                 return 1;
692                         }
693
694                         /* If the exec failed, we fall through to trying to find
695                          * all the needed libraries ourselves by rummaging about
696                          * in the ELF headers... */
697                 }
698         }
699 #endif
700
701         dynsec = elf_find_section_type(SHT_DYNAMIC, ehdr);
702         if (dynsec) {
703                 dynamic = (Elf32_Dyn*)(byteswap32_to_host(dynsec->sh_offset) + (intptr_t)ehdr);
704                 find_needed_libraries(ehdr, dynamic, is_suid);
705         }
706
707         return 0;
708 }
709
710 int main( int argc, char** argv)
711 {
712         int multi=0;
713         int got_em_all=1;
714         char *filename = NULL;
715         struct library *cur;
716
717         if (argc < 2) {
718                 fprintf(stderr, "ldd: missing file arguments\n");
719                 fprintf(stderr, "Try `ldd --help' for more information.\n");
720                 exit(EXIT_FAILURE);
721         }
722         if (argc > 2) {
723                 multi++;
724         }
725
726         while (--argc > 0) {
727                 ++argv;
728
729                 if(strcmp(*argv, "--")==0) {
730                         /* Ignore "--" */
731                         continue;
732                 }
733
734                 if(strcmp(*argv, "--help")==0) {
735                         fprintf(stderr, "Usage: ldd [OPTION]... FILE...\n");
736                         fprintf(stderr, "\t--help\t\tprint this help and exit\n");
737                         exit(EXIT_FAILURE);
738                 }
739
740                 filename=*argv;
741                 if (!filename) {
742                         fprintf(stderr, "No filename specified.\n");
743                         exit(EXIT_FAILURE);
744                 }
745
746                 if (multi) {
747                         printf("%s:\n", *argv);
748                 }
749
750                 map_cache();
751
752                 if (find_dependancies(filename)!=0)
753                         continue;
754
755                 while(got_em_all) {
756                         got_em_all=0;
757                         /* Keep walking the list till everybody is resolved */
758                         for (cur = lib_list; cur; cur=cur->next) {
759                                 if (cur->resolved == 0 && cur->path) {
760                                         got_em_all=1;
761                                         //printf("checking sub-depends for '%s\n", cur->path);
762                                         find_dependancies(cur->path);
763                                         cur->resolved = 1;
764                                 }
765                         }
766                 }
767
768                 unmap_cache();
769
770                 /* Print the list */
771                 got_em_all=0;
772                 for (cur = lib_list; cur; cur=cur->next) {
773                         got_em_all=1;
774                         printf("\t%s => %s (0x00000000)\n", cur->name, cur->path);
775                 }
776                 if (interp && interpreter_already_found==1)
777                         printf("\t%s => %s (0x00000000)\n", interp, interp);
778                 else
779                         printf("\tnot a dynamic executable\n");
780
781                 for (cur = lib_list; cur; cur=cur->next) {
782                         free(cur->name);
783                         cur->name=NULL;
784                         if (cur->path && cur->path != not_found) {
785                                 free(cur->path);
786                                 cur->path=NULL;
787                         }
788                 }
789                 lib_list=NULL;
790         }
791
792         return 0;
793 }
794