]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - usr.bin/ldd/ldd.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.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 /*
53  * 32-bit ELF data structures can only be used if the system header[s] declare
54  * them.  There is no official macro for determining whether they are declared,
55  * so check for the existence of one of the 32-macros defined in elf(5).
56  */
57 #ifdef ELF32_R_TYPE
58 #define ELF32_SUPPORTED
59 #endif
60
61 #define LDD_SETENV(name, value, overwrite) do {         \
62         setenv("LD_" name, value, overwrite);           \
63         setenv("LD_32_" name, value, overwrite);        \
64 } while (0)
65
66 #define LDD_UNSETENV(name) do {         \
67         unsetenv("LD_" name);           \
68         unsetenv("LD_32_" name);        \
69 } while (0)
70
71 static int      is_executable(const char *fname, int fd, int *is_shlib,
72                     int *type);
73 static void     usage(void);
74
75 #define TYPE_UNKNOWN    0
76 #define TYPE_AOUT       1
77 #define TYPE_ELF        2       /* Architecture default */
78 #if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED)
79 #define TYPE_ELF32      3       /* Explicit 32 bits on architectures >32 bits */
80
81 #define _PATH_LDD32     "/usr/bin/ldd32"
82
83 static int
84 execldd32(char *file, char *fmt1, char *fmt2, int aflag, int vflag)
85 {
86         char *argv[8];
87         int i, rval, status;
88
89         LDD_UNSETENV("TRACE_LOADED_OBJECTS");
90         rval = 0;
91         i = 0;
92         argv[i++] = strdup(_PATH_LDD32);
93         if (aflag)
94                 argv[i++] = strdup("-a");
95         if (vflag)
96                 argv[i++] = strdup("-v");
97         if (fmt1 != NULL) {
98                 argv[i++] = strdup("-f");
99                 argv[i++] = strdup(fmt1);
100         }
101         if (fmt2 != NULL) {
102                 argv[i++] = strdup("-f");
103                 argv[i++] = strdup(fmt2);
104         }
105         argv[i++] = strdup(file);
106         argv[i++] = NULL;
107
108         switch (fork()) {
109         case -1:
110                 err(1, "fork");
111                 break;
112         case 0:
113                 execv(_PATH_LDD32, argv);
114                 warn("%s", _PATH_LDD32);
115                 _exit(127);
116                 break;
117         default:
118                 if (wait(&status) < 0)
119                         rval = 1;
120                 else if (WIFSIGNALED(status))
121                         rval = 1;
122                 else if (WIFEXITED(status) && WEXITSTATUS(status) != 0)
123                         rval = 1;
124                 break;
125         }
126         while (i--)
127                 free(argv[i]);
128         LDD_SETENV("TRACE_LOADED_OBJECTS", "yes", 1);
129         return (rval);
130 }
131 #endif
132
133 int
134 main(int argc, char *argv[])
135 {
136         char *fmt1, *fmt2;
137         int rval, c, aflag, vflag;
138
139         aflag = vflag = 0;
140         fmt1 = fmt2 = NULL;
141
142         while ((c = getopt(argc, argv, "af:v")) != -1) {
143                 switch (c) {
144                 case 'a':
145                         aflag++;
146                         break;
147                 case 'f':
148                         if (fmt1 != NULL) {
149                                 if (fmt2 != NULL)
150                                         errx(1, "too many formats");
151                                 fmt2 = optarg;
152                         } else
153                                 fmt1 = optarg;
154                         break;
155                 case 'v':
156                         vflag++;
157                         break;
158                 default:
159                         usage();
160                         /* NOTREACHED */
161                 }
162         }
163         argc -= optind;
164         argv += optind;
165
166         if (vflag && fmt1 != NULL)
167                 errx(1, "-v may not be used with -f");
168
169         if (argc <= 0) {
170                 usage();
171                 /* NOTREACHED */
172         }
173
174 #ifdef __i386__
175         if (vflag) {
176                 for (c = 0; c < argc; c++)
177                         dump_file(argv[c]);
178                 exit(error_count == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
179         }
180 #endif
181
182         rval = 0;
183         for (; argc > 0; argc--, argv++) {
184                 int fd, status, is_shlib, rv, type;
185
186                 if ((fd = open(*argv, O_RDONLY, 0)) < 0) {
187                         warn("%s", *argv);
188                         rval |= 1;
189                         continue;
190                 }
191                 rv = is_executable(*argv, fd, &is_shlib, &type);
192                 close(fd);
193                 if (rv == 0) {
194                         rval |= 1;
195                         continue;
196                 }
197
198                 switch (type) {
199                 case TYPE_ELF:
200                 case TYPE_AOUT:
201                         break;
202 #if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED)
203                 case TYPE_ELF32:
204                         rval |= execldd32(*argv, fmt1, fmt2, aflag, vflag);
205                         continue;
206 #endif
207                 case TYPE_UNKNOWN:
208                 default:
209                         /*
210                          * This shouldn't happen unless is_executable()
211                          * is broken.
212                          */
213                         errx(EDOOFUS, "unknown executable type");
214                 }
215
216                 /* ld.so magic */
217                 LDD_SETENV("TRACE_LOADED_OBJECTS", "yes", 1);
218                 if (fmt1 != NULL)
219                         LDD_SETENV("TRACE_LOADED_OBJECTS_FMT1", fmt1, 1);
220                 if (fmt2 != NULL)
221                         LDD_SETENV("TRACE_LOADED_OBJECTS_FMT2", fmt2, 1);
222
223                 LDD_SETENV("TRACE_LOADED_OBJECTS_PROGNAME", *argv, 1);
224                 if (aflag)
225                         LDD_SETENV("TRACE_LOADED_OBJECTS_ALL", "1", 1);
226                 else if (fmt1 == NULL && fmt2 == NULL)
227                         /* Default formats */
228                         printf("%s:\n", *argv);
229                 fflush(stdout);
230
231                 switch (fork()) {
232                 case -1:
233                         err(1, "fork");
234                         break;
235                 default:
236                         if (wait(&status) < 0) {
237                                 warn("wait");
238                                 rval |= 1;
239                         } else if (WIFSIGNALED(status)) {
240                                 fprintf(stderr, "%s: signal %d\n", *argv,
241                                     WTERMSIG(status));
242                                 rval |= 1;
243                         } else if (WIFEXITED(status) &&
244                             WEXITSTATUS(status) != 0) {
245                                 fprintf(stderr, "%s: exit status %d\n", *argv,
246                                     WEXITSTATUS(status));
247                                 rval |= 1;
248                         }
249                         break;
250                 case 0:
251                         if (is_shlib == 0) {
252                                 execl(*argv, *argv, (char *)NULL);
253                                 warn("%s", *argv);
254                         } else {
255                                 dlopen(*argv, RTLD_TRACE);
256                                 warnx("%s: %s", *argv, dlerror());
257                         }
258                         _exit(1);
259                 }
260         }
261
262         return rval;
263 }
264
265 static void
266 usage(void)
267 {
268
269         fprintf(stderr, "usage: ldd [-a] [-v] [-f format] program ...\n");
270         exit(1);
271 }
272
273 static int
274 is_executable(const char *fname, int fd, int *is_shlib, int *type)
275 {
276         union {
277                 struct exec aout;
278 #if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED)
279                 Elf32_Ehdr elf32;
280 #endif
281                 Elf_Ehdr elf;
282         } hdr;
283         int n;
284
285         *is_shlib = 0;
286         *type = TYPE_UNKNOWN;
287
288         if ((n = read(fd, &hdr, sizeof(hdr))) == -1) {
289                 warn("%s: can't read program header", fname);
290                 return (0);
291         }
292
293         if ((size_t)n >= sizeof(hdr.aout) && !N_BADMAG(hdr.aout)) {
294                 /* a.out file */
295                 if ((N_GETFLAG(hdr.aout) & EX_DPMASK) != EX_DYNAMIC
296 #if 1 /* Compatibility */
297                     || hdr.aout.a_entry < __LDPGSZ
298 #endif
299                         ) {
300                         warnx("%s: not a dynamic executable", fname);
301                         return (0);
302                 }
303                 *type = TYPE_AOUT;
304                 return (1);
305         }
306
307 #if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED)
308         if ((size_t)n >= sizeof(hdr.elf32) && IS_ELF(hdr.elf32) &&
309             hdr.elf32.e_ident[EI_CLASS] == ELFCLASS32) {
310                 /* Handle 32 bit ELF objects */
311                 Elf32_Phdr phdr;
312                 int dynamic, i;
313
314                 dynamic = 0;
315                 *type = TYPE_ELF32;
316
317                 if (lseek(fd, hdr.elf32.e_phoff, SEEK_SET) == -1) {
318                         warnx("%s: header too short", fname);
319                         return (0);
320                 }
321                 for (i = 0; i < hdr.elf32.e_phnum; i++) {
322                         if (read(fd, &phdr, hdr.elf32.e_phentsize) !=
323                             sizeof(phdr)) {
324                                 warnx("%s: can't read program header", fname);
325                                 return (0);
326                         }
327                         if (phdr.p_type == PT_DYNAMIC) {
328                                 dynamic = 1;
329                                 break;
330                         }
331                 }
332
333                 if (!dynamic) {
334                         warnx("%s: not a dynamic ELF executable", fname);
335                         return (0);
336                 }
337                 if (hdr.elf32.e_type == ET_DYN) {
338                         if (hdr.elf32.e_ident[EI_OSABI] == ELFOSABI_FREEBSD) {
339                                 *is_shlib = 1;
340                                 return (1);
341                         }
342                         warnx("%s: not a FreeBSD ELF shared object", fname);
343                         return (0);
344                 }
345
346                 return (1);
347         }
348 #endif
349
350         if ((size_t)n >= sizeof(hdr.elf) && IS_ELF(hdr.elf) &&
351             hdr.elf.e_ident[EI_CLASS] == ELF_TARG_CLASS) {
352                 /* Handle default ELF objects on this architecture */
353                 Elf_Phdr phdr;
354                 int dynamic, i;
355
356                 dynamic = 0;
357                 *type = TYPE_ELF;
358
359                 if (lseek(fd, hdr.elf.e_phoff, SEEK_SET) == -1) {
360                         warnx("%s: header too short", fname);
361                         return (0);
362                 }
363                 for (i = 0; i < hdr.elf.e_phnum; i++) {
364                         if (read(fd, &phdr, hdr.elf.e_phentsize)
365                            != sizeof(phdr)) {
366                                 warnx("%s: can't read program header", fname);
367                                 return (0);
368                         }
369                         if (phdr.p_type == PT_DYNAMIC) {
370                                 dynamic = 1;
371                                 break;
372                         }
373                 }
374
375                 if (!dynamic) {
376                         warnx("%s: not a dynamic ELF executable", fname);
377                         return (0);
378                 }
379                 if (hdr.elf.e_type == ET_DYN) {
380                         if (hdr.elf.e_ident[EI_OSABI] == ELFOSABI_FREEBSD) {
381                                 *is_shlib = 1;
382                                 return (1);
383                         }
384                         warnx("%s: not a FreeBSD ELF shared object", fname);
385                         return (0);
386                 }
387
388                 return (1);
389         }
390
391         warnx("%s: not a dynamic executable", fname);
392         return (0);
393 }