]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - usr.bin/ldd/ldd.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / usr.bin / ldd / ldd.c
1 /*
2  * Copyright (c) 1993 Paul Kranenburg
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by Paul Kranenburg.
16  * 4. The name of the author may not be used to endorse or promote products
17  *    derived from this software without specific prior written permission
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
33
34 #include <sys/wait.h>
35
36 #include <machine/elf.h>
37
38 #include <arpa/inet.h>
39
40 #include <a.out.h>
41 #include <dlfcn.h>
42 #include <err.h>
43 #include <errno.h>
44 #include <fcntl.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <unistd.h>
49
50 #include "extern.h"
51
52 #ifdef COMPAT_32BIT
53 #define LD_     "LD_32_"
54 #else
55 #define LD_     "LD_"
56 #endif
57
58 /*
59  * 32-bit ELF data structures can only be used if the system header[s] declare
60  * them.  There is no official macro for determining whether they are declared,
61  * so check for the existence of one of the 32-macros defined in elf(5).
62  */
63 #ifdef ELF32_R_TYPE
64 #define ELF32_SUPPORTED
65 #endif
66
67 static int      is_executable(const char *fname, int fd, int *is_shlib,
68                     int *type);
69 static void     usage(void);
70
71 #define TYPE_UNKNOWN    0
72 #define TYPE_AOUT       1
73 #define TYPE_ELF        2       /* Architecture default */
74 #if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED)
75 #define TYPE_ELF32      3       /* Explicit 32 bits on architectures >32 bits */
76
77 #define _PATH_LDD32     "/usr/bin/ldd32"
78
79 static int
80 execldd32(char *file, char *fmt1, char *fmt2, int aflag, int vflag)
81 {
82         char *argv[8];
83         int i, rval, status;
84
85         unsetenv(LD_ "TRACE_LOADED_OBJECTS");
86         rval = 0;
87         i = 0;
88         argv[i++] = strdup(_PATH_LDD32);
89         if (aflag)
90                 argv[i++] = strdup("-a");
91         if (vflag)
92                 argv[i++] = strdup("-v");
93         if (fmt1 != NULL) {
94                 argv[i++] = strdup("-f");
95                 argv[i++] = strdup(fmt1);
96         }
97         if (fmt2 != NULL) {
98                 argv[i++] = strdup("-f");
99                 argv[i++] = strdup(fmt2);
100         }
101         argv[i++] = strdup(file);
102         argv[i++] = NULL;
103
104         switch (fork()) {
105         case -1:
106                 err(1, "fork");
107                 break;
108         case 0:
109                 execv(_PATH_LDD32, argv);
110                 warn("%s", _PATH_LDD32);
111                 _exit(127);
112                 break;
113         default:
114                 if (wait(&status) < 0)
115                         rval = 1;
116                 else if (WIFSIGNALED(status))
117                         rval = 1;
118                 else if (WIFEXITED(status) && WEXITSTATUS(status) != 0)
119                         rval = 1;
120                 break;
121         }
122         while (i--)
123                 free(argv[i]);
124         setenv(LD_ "TRACE_LOADED_OBJECTS", "yes", 1);
125         return (rval);
126 }
127 #endif
128
129 int
130 main(int argc, char *argv[])
131 {
132         char *fmt1, *fmt2;
133         int rval, c, aflag, vflag;
134
135         aflag = vflag = 0;
136         fmt1 = fmt2 = NULL;
137
138         while ((c = getopt(argc, argv, "af:v")) != -1) {
139                 switch (c) {
140                 case 'a':
141                         aflag++;
142                         break;
143                 case 'f':
144                         if (fmt1 != NULL) {
145                                 if (fmt2 != NULL)
146                                         errx(1, "too many formats");
147                                 fmt2 = optarg;
148                         } else
149                                 fmt1 = optarg;
150                         break;
151                 case 'v':
152                         vflag++;
153                         break;
154                 default:
155                         usage();
156                         /* NOTREACHED */
157                 }
158         }
159         argc -= optind;
160         argv += optind;
161
162         if (vflag && fmt1 != NULL)
163                 errx(1, "-v may not be used with -f");
164
165         if (argc <= 0) {
166                 usage();
167                 /* NOTREACHED */
168         }
169
170 #ifdef __i386__
171         if (vflag) {
172                 for (c = 0; c < argc; c++)
173                         dump_file(argv[c]);
174                 exit(error_count == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
175         }
176 #endif
177
178         rval = 0;
179         for (; argc > 0; argc--, argv++) {
180                 int fd, status, is_shlib, rv, type;
181
182                 if ((fd = open(*argv, O_RDONLY, 0)) < 0) {
183                         warn("%s", *argv);
184                         rval |= 1;
185                         continue;
186                 }
187                 rv = is_executable(*argv, fd, &is_shlib, &type);
188                 close(fd);
189                 if (rv == 0) {
190                         rval |= 1;
191                         continue;
192                 }
193
194                 switch (type) {
195                 case TYPE_ELF:
196                 case TYPE_AOUT:
197                         break;
198 #if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED)
199                 case TYPE_ELF32:
200                         rval |= execldd32(*argv, fmt1, fmt2, aflag, vflag);
201                         continue;
202 #endif
203                 case TYPE_UNKNOWN:
204                 default:
205                         /*
206                          * This shouldn't happen unless is_executable()
207                          * is broken.
208                          */
209                         errx(EDOOFUS, "unknown executable type");
210                 }
211
212                 /* ld.so magic */
213                 setenv(LD_ "TRACE_LOADED_OBJECTS", "yes", 1);
214                 if (fmt1 != NULL)
215                         setenv(LD_ "TRACE_LOADED_OBJECTS_FMT1", fmt1, 1);
216                 if (fmt2 != NULL)
217                         setenv(LD_ "TRACE_LOADED_OBJECTS_FMT2", fmt2, 1);
218
219                 setenv(LD_ "TRACE_LOADED_OBJECTS_PROGNAME", *argv, 1);
220                 if (aflag)
221                         setenv(LD_ "TRACE_LOADED_OBJECTS_ALL", "1", 1);
222                 else if (fmt1 == NULL && fmt2 == NULL)
223                         /* Default formats */
224                         printf("%s:\n", *argv);
225                 fflush(stdout);
226
227                 switch (fork()) {
228                 case -1:
229                         err(1, "fork");
230                         break;
231                 default:
232                         if (wait(&status) < 0) {
233                                 warn("wait");
234                                 rval |= 1;
235                         } else if (WIFSIGNALED(status)) {
236                                 fprintf(stderr, "%s: signal %d\n", *argv,
237                                     WTERMSIG(status));
238                                 rval |= 1;
239                         } else if (WIFEXITED(status) &&
240                             WEXITSTATUS(status) != 0) {
241                                 fprintf(stderr, "%s: exit status %d\n", *argv,
242                                     WEXITSTATUS(status));
243                                 rval |= 1;
244                         }
245                         break;
246                 case 0:
247                         if (is_shlib == 0) {
248                                 execl(*argv, *argv, (char *)NULL);
249                                 warn("%s", *argv);
250                         } else {
251                                 dlopen(*argv, RTLD_TRACE);
252                                 warnx("%s: %s", *argv, dlerror());
253                         }
254                         _exit(1);
255                 }
256         }
257
258         return rval;
259 }
260
261 static void
262 usage(void)
263 {
264
265         fprintf(stderr, "usage: ldd [-a] [-v] [-f format] program ...\n");
266         exit(1);
267 }
268
269 static int
270 is_executable(const char *fname, int fd, int *is_shlib, int *type)
271 {
272         union {
273                 struct exec aout;
274 #if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED)
275                 Elf32_Ehdr elf32;
276 #endif
277                 Elf_Ehdr elf;
278         } hdr;
279         int n;
280
281         *is_shlib = 0;
282         *type = TYPE_UNKNOWN;
283
284         if ((n = read(fd, &hdr, sizeof(hdr))) == -1) {
285                 warn("%s: can't read program header", fname);
286                 return (0);
287         }
288
289         if ((size_t)n >= sizeof(hdr.aout) && !N_BADMAG(hdr.aout)) {
290                 /* a.out file */
291                 if ((N_GETFLAG(hdr.aout) & EX_DPMASK) != EX_DYNAMIC
292 #if 1 /* Compatibility */
293                     || hdr.aout.a_entry < __LDPGSZ
294 #endif
295                         ) {
296                         warnx("%s: not a dynamic executable", fname);
297                         return (0);
298                 }
299                 *type = TYPE_AOUT;
300                 return (1);
301         }
302
303 #if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED)
304         if ((size_t)n >= sizeof(hdr.elf32) && IS_ELF(hdr.elf32) &&
305             hdr.elf32.e_ident[EI_CLASS] == ELFCLASS32) {
306                 /* Handle 32 bit ELF objects */
307                 Elf32_Phdr phdr;
308                 int dynamic, i;
309
310                 dynamic = 0;
311                 *type = TYPE_ELF32;
312
313                 if (lseek(fd, hdr.elf32.e_phoff, SEEK_SET) == -1) {
314                         warnx("%s: header too short", fname);
315                         return (0);
316                 }
317                 for (i = 0; i < hdr.elf32.e_phnum; i++) {
318                         if (read(fd, &phdr, hdr.elf32.e_phentsize) !=
319                             sizeof(phdr)) {
320                                 warnx("%s: can't read program header", fname);
321                                 return (0);
322                         }
323                         if (phdr.p_type == PT_DYNAMIC) {
324                                 dynamic = 1;
325                                 break;
326                         }
327                 }
328
329                 if (!dynamic) {
330                         warnx("%s: not a dynamic ELF executable", fname);
331                         return (0);
332                 }
333                 if (hdr.elf32.e_type == ET_DYN) {
334                         if (hdr.elf32.e_ident[EI_OSABI] == ELFOSABI_FREEBSD) {
335                                 *is_shlib = 1;
336                                 return (1);
337                         }
338                         warnx("%s: not a FreeBSD ELF shared object", fname);
339                         return (0);
340                 }
341
342                 return (1);
343         }
344 #endif
345
346         if ((size_t)n >= sizeof(hdr.elf) && IS_ELF(hdr.elf) &&
347             hdr.elf.e_ident[EI_CLASS] == ELF_TARG_CLASS) {
348                 /* Handle default ELF objects on this architecture */
349                 Elf_Phdr phdr;
350                 int dynamic, i;
351
352                 dynamic = 0;
353                 *type = TYPE_ELF;
354
355                 if (lseek(fd, hdr.elf.e_phoff, SEEK_SET) == -1) {
356                         warnx("%s: header too short", fname);
357                         return (0);
358                 }
359                 for (i = 0; i < hdr.elf.e_phnum; i++) {
360                         if (read(fd, &phdr, hdr.elf.e_phentsize)
361                            != sizeof(phdr)) {
362                                 warnx("%s: can't read program header", fname);
363                                 return (0);
364                         }
365                         if (phdr.p_type == PT_DYNAMIC) {
366                                 dynamic = 1;
367                                 break;
368                         }
369                 }
370
371                 if (!dynamic) {
372                         warnx("%s: not a dynamic ELF executable", fname);
373                         return (0);
374                 }
375                 if (hdr.elf.e_type == ET_DYN) {
376                         if (hdr.elf.e_ident[EI_OSABI] == ELFOSABI_FREEBSD) {
377                                 *is_shlib = 1;
378                                 return (1);
379                         }
380                         warnx("%s: not a FreeBSD ELF shared object", fname);
381                         return (0);
382                 }
383
384                 return (1);
385         }
386
387         warnx("%s: not a dynamic executable", fname);
388         return (0);
389 }