OSDN Git Service

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