xref: /freebsd/usr.bin/ldd/ldd.c (revision 2f6a179eb910129fb812c1ad1bdc300da1203dc0)
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 <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 
60 static int	is_executable(const char *fname, int fd, int *is_shlib,
61 		    int *type);
62 static 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 
78 const 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)
86 const 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 
95 int
96 main(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 
228 static void
229 usage(void)
230 {
231 
232 	fprintf(stderr, "usage: ldd [-a] [-v] [-f format] program ...\n");
233 	exit(1);
234 }
235 
236 static int
237 is_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