xref: /freebsd/usr.bin/ldd/ldd.c (revision 3cbb4cc200f8a0ad7ed08233425ea54524a21f1c)
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 	Elf_Phdr phdr, dynphdr;
293 	Elf_Dyn *dynp;
294 	void *dyndata;
295 #if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED)
296 	Elf32_Phdr phdr32, dynphdr32;
297 	Elf32_Dyn *dynp32;
298 #endif
299 	int df1pie, dynamic, i, n;
300 
301 	*is_shlib = 0;
302 	*type = TYPE_UNKNOWN;
303 	df1pie = 0;
304 
305 	if ((n = read(fd, &hdr, sizeof(hdr))) == -1) {
306 		warn("%s: can't read program header", fname);
307 		return (0);
308 	}
309 
310 #ifdef AOUT_SUPPORTED
311 	if ((size_t)n >= sizeof(hdr.aout) && !N_BADMAG(hdr.aout)) {
312 		/* a.out file */
313 		if ((N_GETFLAG(hdr.aout) & EX_DPMASK) != EX_DYNAMIC
314 #if 1 /* Compatibility */
315 		    || hdr.aout.a_entry < __LDPGSZ
316 #endif
317 			) {
318 			warnx("%s: not a dynamic executable", fname);
319 			return (0);
320 		}
321 		*type = TYPE_AOUT;
322 		warnx("%s: aout support is deprecated", fname);
323 		return (1);
324 	}
325 #endif
326 
327 #if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED)
328 	if ((size_t)n >= sizeof(hdr.elf32) && IS_ELF(hdr.elf32) &&
329 	    hdr.elf32.e_ident[EI_CLASS] == ELFCLASS32) {
330 		/* Handle 32 bit ELF objects */
331 
332 		dynamic = 0;
333 		*type = TYPE_ELF32;
334 
335 		if (lseek(fd, hdr.elf32.e_phoff, SEEK_SET) == -1) {
336 			warnx("%s: header too short", fname);
337 			return (0);
338 		}
339 		for (i = 0; i < hdr.elf32.e_phnum; i++) {
340 			if (read(fd, &phdr32, hdr.elf32.e_phentsize) !=
341 			    sizeof(phdr32)) {
342 				warnx("%s: can't read program header", fname);
343 				return (0);
344 			}
345 			if (phdr32.p_type == PT_DYNAMIC) {
346 				dynamic = 1;
347 				dynphdr32 = phdr32;
348 				break;
349 			}
350 		}
351 
352 		if (!dynamic) {
353 			warnx("%s: not a dynamic ELF executable", fname);
354 			return (0);
355 		}
356 
357 		if (hdr.elf32.e_type == ET_DYN) {
358 			if (lseek(fd, dynphdr32.p_offset, SEEK_SET) == -1) {
359 				warnx("%s: dynamic segment out of range",
360 				    fname);
361 				return (0);
362 			}
363 			dyndata = malloc(dynphdr32.p_filesz);
364 			if (dyndata == NULL) {
365 				warn("malloc");
366 				return (0);
367 			}
368 			if (read(fd, dyndata, dynphdr32.p_filesz) !=
369 			    (ssize_t)dynphdr32.p_filesz) {
370 				free(dyndata);
371 				warnx("%s: can't read dynamic segment", fname);
372 				return (0);
373 			}
374 			for (dynp32 = dyndata; dynp32->d_tag != DT_NULL;
375 			    dynp32++) {
376 				if (dynp32->d_tag != DT_FLAGS_1)
377 					continue;
378 				df1pie = (dynp32->d_un.d_val & DF_1_PIE) != 0;
379 				break;
380 			}
381 			free(dyndata);
382 
383 			if (hdr.elf32.e_ident[EI_OSABI] == ELFOSABI_FREEBSD) {
384 				if (!df1pie)
385 					*is_shlib = 1;
386 				return (1);
387 			}
388 			warnx("%s: not a FreeBSD ELF shared object", fname);
389 			return (0);
390 		}
391 
392 		return (1);
393 	}
394 #endif
395 
396 	if ((size_t)n >= sizeof(hdr.elf) && IS_ELF(hdr.elf) &&
397 	    hdr.elf.e_ident[EI_CLASS] == ELF_TARG_CLASS) {
398 		/* Handle default ELF objects on this architecture */
399 
400 		dynamic = 0;
401 		*type = TYPE_ELF;
402 
403 		if (lseek(fd, hdr.elf.e_phoff, SEEK_SET) == -1) {
404 			warnx("%s: header too short", fname);
405 			return (0);
406 		}
407 		for (i = 0; i < hdr.elf.e_phnum; i++) {
408 			if (read(fd, &phdr, hdr.elf.e_phentsize)
409 			   != sizeof(phdr)) {
410 				warnx("%s: can't read program header", fname);
411 				return (0);
412 			}
413 			if (phdr.p_type == PT_DYNAMIC) {
414 				dynamic = 1;
415 				dynphdr = phdr;
416 				break;
417 			}
418 		}
419 
420 		if (!dynamic) {
421 			warnx("%s: not a dynamic ELF executable", fname);
422 			return (0);
423 		}
424 
425 		if (hdr.elf.e_type == ET_DYN) {
426 			if (lseek(fd, dynphdr.p_offset, SEEK_SET) == -1) {
427 				warnx("%s: dynamic segment out of range",
428 				    fname);
429 				return (0);
430 			}
431 			dyndata = malloc(dynphdr.p_filesz);
432 			if (dyndata == NULL) {
433 				warn("malloc");
434 				return (0);
435 			}
436 			if (read(fd, dyndata, dynphdr.p_filesz) !=
437 			    (ssize_t)dynphdr.p_filesz) {
438 				free(dyndata);
439 				warnx("%s: can't read dynamic segment", fname);
440 				return (0);
441 			}
442 			for (dynp = dyndata; dynp->d_tag != DT_NULL; dynp++) {
443 				if (dynp->d_tag != DT_FLAGS_1)
444 					continue;
445 				df1pie = (dynp->d_un.d_val & DF_1_PIE) != 0;
446 				break;
447 			}
448 			free(dyndata);
449 
450 			switch (hdr.elf.e_ident[EI_OSABI]) {
451 			case ELFOSABI_FREEBSD:
452 				if (!df1pie)
453 					*is_shlib = 1;
454 				return (1);
455 #ifdef __ARM_EABI__
456 			case ELFOSABI_NONE:
457 				if (hdr.elf.e_machine != EM_ARM)
458 					break;
459 				if (EF_ARM_EABI_VERSION(hdr.elf.e_flags) <
460 				    EF_ARM_EABI_FREEBSD_MIN)
461 					break;
462 				*is_shlib = 1;
463 				return (1);
464 #endif
465 			}
466 			warnx("%s: not a FreeBSD ELF shared object", fname);
467 			return (0);
468 		}
469 
470 		return (1);
471 	}
472 
473 	warnx("%s: not a dynamic executable", fname);
474 	return (0);
475 }
476