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