ldd.c revision 294665
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: head/usr.bin/ldd/ldd.c 294665 2016-01-24 15:15:57Z br $");
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
76static int	is_executable(const char *fname, int fd, int *is_shlib,
77		    int *type);
78static 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
88static int
89execldd32(char *file, char *fmt1, char *fmt2, int aflag, int vflag)
90{
91	char *argv[8];
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
138int
139main(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
270static void
271usage(void)
272{
273
274	fprintf(stderr, "usage: ldd [-a] [-v] [-f format] program ...\n");
275	exit(1);
276}
277
278static int
279is_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}
414