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