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