OSDN Git Service

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