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