ldd.c revision 180877
1696Spaul/*
2696Spaul * Copyright (c) 1993 Paul Kranenburg
3696Spaul * All rights reserved.
4696Spaul *
5696Spaul * Redistribution and use in source and binary forms, with or without
6696Spaul * modification, are permitted provided that the following conditions
7696Spaul * are met:
8696Spaul * 1. Redistributions of source code must retain the above copyright
9696Spaul *    notice, this list of conditions and the following disclaimer.
10696Spaul * 2. Redistributions in binary form must reproduce the above copyright
11696Spaul *    notice, this list of conditions and the following disclaimer in the
12696Spaul *    documentation and/or other materials provided with the distribution.
13696Spaul * 3. All advertising materials mentioning features or use of this software
14696Spaul *    must display the following acknowledgement:
15696Spaul *      This product includes software developed by Paul Kranenburg.
16696Spaul * 4. The name of the author may not be used to endorse or promote products
171153Sjkh *    derived from this software without specific prior written permission
18696Spaul *
19696Spaul * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20696Spaul * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21696Spaul * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22696Spaul * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23696Spaul * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24696Spaul * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25696Spaul * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26696Spaul * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27696Spaul * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28696Spaul * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29696Spaul */
30696Spaul
3195648Smarkm#include <sys/cdefs.h>
3295648Smarkm__FBSDID("$FreeBSD: head/usr.bin/ldd/ldd.c 180877 2008-07-28 12:49:16Z edwin $");
3369827Scharnier
34696Spaul#include <sys/wait.h>
3595648Smarkm
3676224Sobrien#include <machine/elf.h>
3795648Smarkm
3895153Smike#include <arpa/inet.h>
3995648Smarkm
40696Spaul#include <a.out.h>
4190172Ssobomax#include <dlfcn.h>
421741Srich#include <err.h>
43180236Sedwin#include <errno.h>
441741Srich#include <fcntl.h>
451741Srich#include <stdio.h>
461741Srich#include <stdlib.h>
471741Srich#include <unistd.h>
48696Spaul
4995648Smarkm#include "extern.h"
5018600Speter
51180646Sedwin/*
52180877Sedwin * 32-bit ELF data structures can only be used if the system header[s] declare
53180877Sedwin * them.  There is no official macro for determining whether they are declared,
54180877Sedwin * so check for the existence of one of the 32-macros defined in elf(5).
55180646Sedwin */
56180877Sedwin#ifdef ELF32_R_TYPE
57180877Sedwin#define	ELF32_SUPPORTED
58180646Sedwin#endif
59180646Sedwin
60180235Sedwinstatic int	is_executable(const char *fname, int fd, int *is_shlib,
61180235Sedwin		    int *type);
62180235Sedwinstatic void	usage(void);
63180234Sedwin
64180235Sedwin#define	TYPE_UNKNOWN	0
65180235Sedwin#define	TYPE_AOUT	1
66180235Sedwin#define	TYPE_ELF	2	/* Architecture default */
67180646Sedwin#if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED)
68180236Sedwin#define	TYPE_ELF32	3	/* Explicit 32 bits on architectures >32 bits */
69180236Sedwin#endif
70696Spaul
71180235Sedwin#define	ENV_OBJECTS		0
72180235Sedwin#define	ENV_OBJECTS_FMT1	1
73180235Sedwin#define	ENV_OBJECTS_FMT2	2
74180235Sedwin#define	ENV_OBJECTS_PROGNAME	3
75180235Sedwin#define	ENV_OBJECTS_ALL		4
76180235Sedwin#define	ENV_LAST		5
77180235Sedwin
78180235Sedwinconst char	*envdef[ENV_LAST] = {
79180235Sedwin	"LD_TRACE_LOADED_OBJECTS",
80180235Sedwin	"LD_TRACE_LOADED_OBJECTS_FMT1",
81180235Sedwin	"LD_TRACE_LOADED_OBJECTS_FMT2",
82180235Sedwin	"LD_TRACE_LOADED_OBJECTS_PROGNAME",
83180235Sedwin	"LD_TRACE_LOADED_OBJECTS_ALL",
84180235Sedwin};
85180646Sedwin#if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED)
86180236Sedwinconst char	*env32[ENV_LAST] = {
87180236Sedwin	"LD_32_TRACE_LOADED_OBJECTS",
88180236Sedwin	"LD_32_TRACE_LOADED_OBJECTS_FMT1",
89180236Sedwin	"LD_32_TRACE_LOADED_OBJECTS_FMT2",
90180236Sedwin	"LD_32_TRACE_LOADED_OBJECTS_PROGNAME",
91180236Sedwin	"LD_32_TRACE_LOADED_OBJECTS_ALL",
92180236Sedwin};
93180236Sedwin#endif
94180235Sedwin
95696Spaulint
9695648Smarkmmain(int argc, char *argv[])
97696Spaul{
98180234Sedwin	char *fmt1, *fmt2;
99180234Sedwin	int rval, c, aflag, vflag;
100696Spaul
10190755Sobrien	aflag = vflag = 0;
102180234Sedwin	fmt1 = fmt2 = NULL;
10390755Sobrien
104180234Sedwin	while ((c = getopt(argc, argv, "af:v")) != -1) {
105696Spaul		switch (c) {
10690755Sobrien		case 'a':
10790755Sobrien			aflag++;
10890755Sobrien			break;
10918598Speter		case 'f':
110180234Sedwin			if (fmt1 != NULL) {
111180234Sedwin				if (fmt2 != NULL)
11269827Scharnier					errx(1, "too many formats");
11318598Speter				fmt2 = optarg;
11418598Speter			} else
11518598Speter				fmt1 = optarg;
11618598Speter			break;
117180234Sedwin		case 'v':
118180234Sedwin			vflag++;
119180234Sedwin			break;
120696Spaul		default:
121696Spaul			usage();
122180234Sedwin			/* NOTREACHED */
123696Spaul		}
124696Spaul	}
125696Spaul	argc -= optind;
126696Spaul	argv += optind;
127696Spaul
128180234Sedwin	if (vflag && fmt1 != NULL)
12918600Speter		errx(1, "-v may not be used with -f");
13018600Speter
131696Spaul	if (argc <= 0) {
132696Spaul		usage();
133180234Sedwin		/* NOTREACHED */
134696Spaul	}
135696Spaul
13639354Sdfr#ifdef __i386__
13718600Speter	if (vflag) {
13818600Speter		for (c = 0; c < argc; c++)
13918600Speter			dump_file(argv[c]);
14018600Speter		exit(error_count == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
14118600Speter	}
14239354Sdfr#endif
14318600Speter
1441741Srich	rval = 0;
145180234Sedwin	for (; argc > 0; argc--, argv++) {
146180235Sedwin		int fd, status, is_shlib, rv, type;
147180235Sedwin		const char **env;
148696Spaul
149696Spaul		if ((fd = open(*argv, O_RDONLY, 0)) < 0) {
1501741Srich			warn("%s", *argv);
151696Spaul			rval |= 1;
152696Spaul			continue;
153696Spaul		}
154180235Sedwin		rv = is_executable(*argv, fd, &is_shlib, &type);
155180235Sedwin		close(fd);
156180235Sedwin		if (rv == 0) {
157696Spaul			rval |= 1;
158696Spaul			continue;
159696Spaul		}
16035575Sdfr
161180236Sedwin		switch (type) {
162180236Sedwin		case TYPE_ELF:
163180236Sedwin		case TYPE_AOUT:
164180236Sedwin			env = envdef;
165180236Sedwin			break;
166180646Sedwin#if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED)
167180236Sedwin		case TYPE_ELF32:
168180236Sedwin			env = env32;
169180236Sedwin			break;
170180236Sedwin#endif
171180236Sedwin		case TYPE_UNKNOWN:
172180236Sedwin		default:
173180236Sedwin			/*
174180236Sedwin			 * This shouldn't happen unless is_executable()
175180236Sedwin			 * is broken.
176180236Sedwin			 */
177180236Sedwin			errx(EDOOFUS, "unknown executable type");
178180236Sedwin		}
179180236Sedwin
180180235Sedwin		/* ld.so magic */
181180235Sedwin		setenv(env[ENV_OBJECTS], "yes", 1);
182180235Sedwin		if (fmt1 != NULL)
183180235Sedwin			setenv(env[ENV_OBJECTS_FMT1], fmt1, 1);
184180235Sedwin		if (fmt2 != NULL)
185180235Sedwin			setenv(env[ENV_OBJECTS_FMT2], fmt2, 1);
18635575Sdfr
187180235Sedwin		setenv(env[ENV_OBJECTS_PROGNAME], *argv, 1);
188180234Sedwin		if (aflag)
189180235Sedwin			setenv(env[ENV_OBJECTS_ALL], "1", 1);
19090755Sobrien		else if (fmt1 == NULL && fmt2 == NULL)
19118598Speter			/* Default formats */
19218598Speter			printf("%s:\n", *argv);
1931153Sjkh		fflush(stdout);
194696Spaul
195696Spaul		switch (fork()) {
196696Spaul		case -1:
1971741Srich			err(1, "fork");
198696Spaul			break;
199696Spaul		default:
2001741Srich			if (wait(&status) <= 0) {
2011741Srich				warn("wait");
2021741Srich				rval |= 1;
2031741Srich			} else if (WIFSIGNALED(status)) {
204180234Sedwin				fprintf(stderr, "%s: signal %d\n", *argv,
205180234Sedwin				    WTERMSIG(status));
206696Spaul				rval |= 1;
207696Spaul			} else if (WIFEXITED(status) && WEXITSTATUS(status)) {
208180234Sedwin				fprintf(stderr, "%s: exit status %d\n", *argv,
209180234Sedwin				    WEXITSTATUS(status));
210696Spaul				rval |= 1;
211696Spaul			}
212696Spaul			break;
213696Spaul		case 0:
214105439Ssobomax			if (is_shlib == 0) {
21590172Ssobomax				execl(*argv, *argv, (char *)NULL);
21690172Ssobomax				warn("%s", *argv);
217105439Ssobomax			} else {
218105439Ssobomax				dlopen(*argv, RTLD_TRACE);
219105439Ssobomax				warnx("%s: %s", *argv, dlerror());
22090172Ssobomax			}
221696Spaul			_exit(1);
222696Spaul		}
223696Spaul	}
224696Spaul
225696Spaul	return rval;
226696Spaul}
227180235Sedwin
228180235Sedwinstatic void
229180235Sedwinusage(void)
230180235Sedwin{
231180235Sedwin
232180235Sedwin	fprintf(stderr, "usage: ldd [-a] [-v] [-f format] program ...\n");
233180235Sedwin	exit(1);
234180235Sedwin}
235180235Sedwin
236180235Sedwinstatic int
237180235Sedwinis_executable(const char *fname, int fd, int *is_shlib, int *type)
238180235Sedwin{
239180235Sedwin	union {
240180235Sedwin		struct exec aout;
241180646Sedwin#if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED)
242180236Sedwin		Elf32_Ehdr elf32;
243180646Sedwin#endif
244180235Sedwin		Elf_Ehdr elf;
245180235Sedwin	} hdr;
246180235Sedwin	int n;
247180235Sedwin
248180235Sedwin	*is_shlib = 0;
249180235Sedwin	*type = TYPE_UNKNOWN;
250180235Sedwin
251180235Sedwin	if ((n = read(fd, &hdr, sizeof(hdr))) == -1) {
252180235Sedwin		warn("%s: can't read program header", fname);
253180235Sedwin		return (0);
254180235Sedwin	}
255180235Sedwin
256180235Sedwin	if ((size_t)n >= sizeof(hdr.aout) && !N_BADMAG(hdr.aout)) {
257180235Sedwin		/* a.out file */
258180235Sedwin		if ((N_GETFLAG(hdr.aout) & EX_DPMASK) != EX_DYNAMIC
259180235Sedwin#if 1 /* Compatibility */
260180235Sedwin		    || hdr.aout.a_entry < __LDPGSZ
261180235Sedwin#endif
262180235Sedwin			) {
263180235Sedwin			warnx("%s: not a dynamic executable", fname);
264180235Sedwin			return (0);
265180235Sedwin		}
266180235Sedwin		*type = TYPE_AOUT;
267180235Sedwin		return (1);
268180235Sedwin	}
269180235Sedwin
270180646Sedwin#if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED)
271180236Sedwin	if ((size_t)n >= sizeof(hdr.elf32) && IS_ELF(hdr.elf32) &&
272180236Sedwin	    hdr.elf32.e_ident[EI_CLASS] == ELFCLASS32) {
273180236Sedwin		/* Handle 32 bit ELF objects */
274180236Sedwin		Elf32_Phdr phdr;
275180236Sedwin		int dynamic, i;
276180236Sedwin
277180236Sedwin		dynamic = 0;
278180236Sedwin		*type = TYPE_ELF32;
279180236Sedwin
280180236Sedwin		if (lseek(fd, hdr.elf32.e_phoff, SEEK_SET) == -1) {
281180236Sedwin			warnx("%s: header too short", fname);
282180236Sedwin			return (0);
283180236Sedwin		}
284180236Sedwin		for (i = 0; i < hdr.elf32.e_phnum; i++) {
285180236Sedwin			if (read(fd, &phdr, hdr.elf32.e_phentsize) !=
286180236Sedwin			    sizeof(phdr)) {
287180236Sedwin				warnx("%s: can't read program header", fname);
288180236Sedwin				return (0);
289180236Sedwin			}
290180236Sedwin			if (phdr.p_type == PT_DYNAMIC) {
291180236Sedwin				dynamic = 1;
292180236Sedwin				break;
293180236Sedwin			}
294180236Sedwin		}
295180236Sedwin
296180236Sedwin		if (!dynamic) {
297180236Sedwin			warnx("%s: not a dynamic ELF executable", fname);
298180236Sedwin			return (0);
299180236Sedwin		}
300180236Sedwin		if (hdr.elf32.e_type == ET_DYN) {
301180236Sedwin			if (hdr.elf32.e_ident[EI_OSABI] & ELFOSABI_FREEBSD) {
302180236Sedwin				*is_shlib = 1;
303180236Sedwin				return (1);
304180236Sedwin			}
305180236Sedwin			warnx("%s: not a FreeBSD ELF shared object", fname);
306180236Sedwin			return (0);
307180236Sedwin		}
308180236Sedwin
309180236Sedwin		return (1);
310180236Sedwin	}
311180236Sedwin#endif
312180236Sedwin
313180235Sedwin	if ((size_t)n >= sizeof(hdr.elf) && IS_ELF(hdr.elf) &&
314180235Sedwin	    hdr.elf.e_ident[EI_CLASS] == ELF_TARG_CLASS) {
315180235Sedwin		/* Handle default ELF objects on this architecture */
316180235Sedwin		Elf_Phdr phdr;
317180235Sedwin		int dynamic, i;
318180235Sedwin
319180235Sedwin		dynamic = 0;
320180235Sedwin		*type = TYPE_ELF;
321180235Sedwin
322180235Sedwin		if (lseek(fd, hdr.elf.e_phoff, SEEK_SET) == -1) {
323180235Sedwin			warnx("%s: header too short", fname);
324180235Sedwin			return (0);
325180235Sedwin		}
326180235Sedwin		for (i = 0; i < hdr.elf.e_phnum; i++) {
327180235Sedwin			if (read(fd, &phdr, hdr.elf.e_phentsize)
328180235Sedwin			   != sizeof(phdr)) {
329180235Sedwin				warnx("%s: can't read program header", fname);
330180235Sedwin				return (0);
331180235Sedwin			}
332180235Sedwin			if (phdr.p_type == PT_DYNAMIC) {
333180235Sedwin				dynamic = 1;
334180235Sedwin				break;
335180235Sedwin			}
336180235Sedwin		}
337180235Sedwin
338180235Sedwin		if (!dynamic) {
339180235Sedwin			warnx("%s: not a dynamic ELF executable", fname);
340180235Sedwin			return (0);
341180235Sedwin		}
342180235Sedwin		if (hdr.elf.e_type == ET_DYN) {
343180235Sedwin			if (hdr.elf.e_ident[EI_OSABI] & ELFOSABI_FREEBSD) {
344180235Sedwin				*is_shlib = 1;
345180235Sedwin				return (1);
346180235Sedwin			}
347180235Sedwin			warnx("%s: not a FreeBSD ELF shared object", fname);
348180235Sedwin			return (0);
349180235Sedwin		}
350180235Sedwin
351180235Sedwin		return (1);
352180235Sedwin	}
353180235Sedwin
354180235Sedwin	warnx("%s: not a dynamic executable", fname);
355180235Sedwin	return (0);
356180235Sedwin}
357