ldd.c revision 180877
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 180877 2008-07-28 12:49:16Z edwin $");
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 <unistd.h>
48
49#include "extern.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
60static int	is_executable(const char *fname, int fd, int *is_shlib,
61		    int *type);
62static void	usage(void);
63
64#define	TYPE_UNKNOWN	0
65#define	TYPE_AOUT	1
66#define	TYPE_ELF	2	/* Architecture default */
67#if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED)
68#define	TYPE_ELF32	3	/* Explicit 32 bits on architectures >32 bits */
69#endif
70
71#define	ENV_OBJECTS		0
72#define	ENV_OBJECTS_FMT1	1
73#define	ENV_OBJECTS_FMT2	2
74#define	ENV_OBJECTS_PROGNAME	3
75#define	ENV_OBJECTS_ALL		4
76#define	ENV_LAST		5
77
78const char	*envdef[ENV_LAST] = {
79	"LD_TRACE_LOADED_OBJECTS",
80	"LD_TRACE_LOADED_OBJECTS_FMT1",
81	"LD_TRACE_LOADED_OBJECTS_FMT2",
82	"LD_TRACE_LOADED_OBJECTS_PROGNAME",
83	"LD_TRACE_LOADED_OBJECTS_ALL",
84};
85#if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED)
86const char	*env32[ENV_LAST] = {
87	"LD_32_TRACE_LOADED_OBJECTS",
88	"LD_32_TRACE_LOADED_OBJECTS_FMT1",
89	"LD_32_TRACE_LOADED_OBJECTS_FMT2",
90	"LD_32_TRACE_LOADED_OBJECTS_PROGNAME",
91	"LD_32_TRACE_LOADED_OBJECTS_ALL",
92};
93#endif
94
95int
96main(int argc, char *argv[])
97{
98	char *fmt1, *fmt2;
99	int rval, c, aflag, vflag;
100
101	aflag = vflag = 0;
102	fmt1 = fmt2 = NULL;
103
104	while ((c = getopt(argc, argv, "af:v")) != -1) {
105		switch (c) {
106		case 'a':
107			aflag++;
108			break;
109		case 'f':
110			if (fmt1 != NULL) {
111				if (fmt2 != NULL)
112					errx(1, "too many formats");
113				fmt2 = optarg;
114			} else
115				fmt1 = optarg;
116			break;
117		case 'v':
118			vflag++;
119			break;
120		default:
121			usage();
122			/* NOTREACHED */
123		}
124	}
125	argc -= optind;
126	argv += optind;
127
128	if (vflag && fmt1 != NULL)
129		errx(1, "-v may not be used with -f");
130
131	if (argc <= 0) {
132		usage();
133		/* NOTREACHED */
134	}
135
136#ifdef __i386__
137	if (vflag) {
138		for (c = 0; c < argc; c++)
139			dump_file(argv[c]);
140		exit(error_count == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
141	}
142#endif
143
144	rval = 0;
145	for (; argc > 0; argc--, argv++) {
146		int fd, status, is_shlib, rv, type;
147		const char **env;
148
149		if ((fd = open(*argv, O_RDONLY, 0)) < 0) {
150			warn("%s", *argv);
151			rval |= 1;
152			continue;
153		}
154		rv = is_executable(*argv, fd, &is_shlib, &type);
155		close(fd);
156		if (rv == 0) {
157			rval |= 1;
158			continue;
159		}
160
161		switch (type) {
162		case TYPE_ELF:
163		case TYPE_AOUT:
164			env = envdef;
165			break;
166#if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED)
167		case TYPE_ELF32:
168			env = env32;
169			break;
170#endif
171		case TYPE_UNKNOWN:
172		default:
173			/*
174			 * This shouldn't happen unless is_executable()
175			 * is broken.
176			 */
177			errx(EDOOFUS, "unknown executable type");
178		}
179
180		/* ld.so magic */
181		setenv(env[ENV_OBJECTS], "yes", 1);
182		if (fmt1 != NULL)
183			setenv(env[ENV_OBJECTS_FMT1], fmt1, 1);
184		if (fmt2 != NULL)
185			setenv(env[ENV_OBJECTS_FMT2], fmt2, 1);
186
187		setenv(env[ENV_OBJECTS_PROGNAME], *argv, 1);
188		if (aflag)
189			setenv(env[ENV_OBJECTS_ALL], "1", 1);
190		else if (fmt1 == NULL && fmt2 == NULL)
191			/* Default formats */
192			printf("%s:\n", *argv);
193		fflush(stdout);
194
195		switch (fork()) {
196		case -1:
197			err(1, "fork");
198			break;
199		default:
200			if (wait(&status) <= 0) {
201				warn("wait");
202				rval |= 1;
203			} else if (WIFSIGNALED(status)) {
204				fprintf(stderr, "%s: signal %d\n", *argv,
205				    WTERMSIG(status));
206				rval |= 1;
207			} else if (WIFEXITED(status) && WEXITSTATUS(status)) {
208				fprintf(stderr, "%s: exit status %d\n", *argv,
209				    WEXITSTATUS(status));
210				rval |= 1;
211			}
212			break;
213		case 0:
214			if (is_shlib == 0) {
215				execl(*argv, *argv, (char *)NULL);
216				warn("%s", *argv);
217			} else {
218				dlopen(*argv, RTLD_TRACE);
219				warnx("%s: %s", *argv, dlerror());
220			}
221			_exit(1);
222		}
223	}
224
225	return rval;
226}
227
228static void
229usage(void)
230{
231
232	fprintf(stderr, "usage: ldd [-a] [-v] [-f format] program ...\n");
233	exit(1);
234}
235
236static int
237is_executable(const char *fname, int fd, int *is_shlib, int *type)
238{
239	union {
240		struct exec aout;
241#if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED)
242		Elf32_Ehdr elf32;
243#endif
244		Elf_Ehdr elf;
245	} hdr;
246	int n;
247
248	*is_shlib = 0;
249	*type = TYPE_UNKNOWN;
250
251	if ((n = read(fd, &hdr, sizeof(hdr))) == -1) {
252		warn("%s: can't read program header", fname);
253		return (0);
254	}
255
256	if ((size_t)n >= sizeof(hdr.aout) && !N_BADMAG(hdr.aout)) {
257		/* a.out file */
258		if ((N_GETFLAG(hdr.aout) & EX_DPMASK) != EX_DYNAMIC
259#if 1 /* Compatibility */
260		    || hdr.aout.a_entry < __LDPGSZ
261#endif
262			) {
263			warnx("%s: not a dynamic executable", fname);
264			return (0);
265		}
266		*type = TYPE_AOUT;
267		return (1);
268	}
269
270#if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED)
271	if ((size_t)n >= sizeof(hdr.elf32) && IS_ELF(hdr.elf32) &&
272	    hdr.elf32.e_ident[EI_CLASS] == ELFCLASS32) {
273		/* Handle 32 bit ELF objects */
274		Elf32_Phdr phdr;
275		int dynamic, i;
276
277		dynamic = 0;
278		*type = TYPE_ELF32;
279
280		if (lseek(fd, hdr.elf32.e_phoff, SEEK_SET) == -1) {
281			warnx("%s: header too short", fname);
282			return (0);
283		}
284		for (i = 0; i < hdr.elf32.e_phnum; i++) {
285			if (read(fd, &phdr, hdr.elf32.e_phentsize) !=
286			    sizeof(phdr)) {
287				warnx("%s: can't read program header", fname);
288				return (0);
289			}
290			if (phdr.p_type == PT_DYNAMIC) {
291				dynamic = 1;
292				break;
293			}
294		}
295
296		if (!dynamic) {
297			warnx("%s: not a dynamic ELF executable", fname);
298			return (0);
299		}
300		if (hdr.elf32.e_type == ET_DYN) {
301			if (hdr.elf32.e_ident[EI_OSABI] & ELFOSABI_FREEBSD) {
302				*is_shlib = 1;
303				return (1);
304			}
305			warnx("%s: not a FreeBSD ELF shared object", fname);
306			return (0);
307		}
308
309		return (1);
310	}
311#endif
312
313	if ((size_t)n >= sizeof(hdr.elf) && IS_ELF(hdr.elf) &&
314	    hdr.elf.e_ident[EI_CLASS] == ELF_TARG_CLASS) {
315		/* Handle default ELF objects on this architecture */
316		Elf_Phdr phdr;
317		int dynamic, i;
318
319		dynamic = 0;
320		*type = TYPE_ELF;
321
322		if (lseek(fd, hdr.elf.e_phoff, SEEK_SET) == -1) {
323			warnx("%s: header too short", fname);
324			return (0);
325		}
326		for (i = 0; i < hdr.elf.e_phnum; i++) {
327			if (read(fd, &phdr, hdr.elf.e_phentsize)
328			   != sizeof(phdr)) {
329				warnx("%s: can't read program header", fname);
330				return (0);
331			}
332			if (phdr.p_type == PT_DYNAMIC) {
333				dynamic = 1;
334				break;
335			}
336		}
337
338		if (!dynamic) {
339			warnx("%s: not a dynamic ELF executable", fname);
340			return (0);
341		}
342		if (hdr.elf.e_type == ET_DYN) {
343			if (hdr.elf.e_ident[EI_OSABI] & ELFOSABI_FREEBSD) {
344				*is_shlib = 1;
345				return (1);
346			}
347			warnx("%s: not a FreeBSD ELF shared object", fname);
348			return (0);
349		}
350
351		return (1);
352	}
353
354	warnx("%s: not a dynamic executable", fname);
355	return (0);
356}
357