xref: /freebsd/usr.bin/ldd/ldd.c (revision d3c1e14b41ef931cf5c1d3e8e26e22daa9854589)
1b9ae52e3SPaul Richards /*
2b9ae52e3SPaul Richards  * Copyright (c) 1993 Paul Kranenburg
3b9ae52e3SPaul Richards  * All rights reserved.
4b9ae52e3SPaul Richards  *
5b9ae52e3SPaul Richards  * Redistribution and use in source and binary forms, with or without
6b9ae52e3SPaul Richards  * modification, are permitted provided that the following conditions
7b9ae52e3SPaul Richards  * are met:
8b9ae52e3SPaul Richards  * 1. Redistributions of source code must retain the above copyright
9b9ae52e3SPaul Richards  *    notice, this list of conditions and the following disclaimer.
10b9ae52e3SPaul Richards  * 2. Redistributions in binary form must reproduce the above copyright
11b9ae52e3SPaul Richards  *    notice, this list of conditions and the following disclaimer in the
12b9ae52e3SPaul Richards  *    documentation and/or other materials provided with the distribution.
13b9ae52e3SPaul Richards  * 3. All advertising materials mentioning features or use of this software
14b9ae52e3SPaul Richards  *    must display the following acknowledgement:
15b9ae52e3SPaul Richards  *      This product includes software developed by Paul Kranenburg.
16b9ae52e3SPaul Richards  * 4. The name of the author may not be used to endorse or promote products
1709e3d49dSJordan K. Hubbard  *    derived from this software without specific prior written permission
18b9ae52e3SPaul Richards  *
19b9ae52e3SPaul Richards  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20b9ae52e3SPaul Richards  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21b9ae52e3SPaul Richards  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22b9ae52e3SPaul Richards  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23b9ae52e3SPaul Richards  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24b9ae52e3SPaul Richards  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25b9ae52e3SPaul Richards  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26b9ae52e3SPaul Richards  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27b9ae52e3SPaul Richards  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28b9ae52e3SPaul Richards  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29b9ae52e3SPaul Richards  */
30b9ae52e3SPaul Richards 
31a53809fdSMark Murray #include <sys/cdefs.h>
32a53809fdSMark Murray __FBSDID("$FreeBSD$");
333e762626SPhilippe Charnier 
34b9ae52e3SPaul Richards #include <sys/wait.h>
35a53809fdSMark Murray 
365e6220d9SDavid E. O'Brien #include <machine/elf.h>
37a53809fdSMark Murray 
38a2cfdda8SMike Barcroft #include <arpa/inet.h>
39a53809fdSMark Murray 
40b9ae52e3SPaul Richards #include <a.out.h>
41c6de4ce7SMaxim Sobolev #include <dlfcn.h>
42699e1b82SRich Murphey #include <err.h>
43699e1b82SRich Murphey #include <fcntl.h>
44699e1b82SRich Murphey #include <stdio.h>
45699e1b82SRich Murphey #include <stdlib.h>
46699e1b82SRich Murphey #include <unistd.h>
47b9ae52e3SPaul Richards 
48a53809fdSMark Murray #include "extern.h"
499731d137SPeter Wemm 
50d3c1e14bSEdwin Groothuis static int	is_executable(const char *fname, int fd, int *is_shlib,
51d3c1e14bSEdwin Groothuis 		    int *type);
52d3c1e14bSEdwin Groothuis static void	usage(void);
53a0d476a9SEdwin Groothuis 
54d3c1e14bSEdwin Groothuis #define	TYPE_UNKNOWN	0
55d3c1e14bSEdwin Groothuis #define	TYPE_AOUT	1
56d3c1e14bSEdwin Groothuis #define	TYPE_ELF	2	/* Architecture default */
57d3c1e14bSEdwin Groothuis 
58d3c1e14bSEdwin Groothuis #define	ENV_OBJECTS		0
59d3c1e14bSEdwin Groothuis #define	ENV_OBJECTS_FMT1	1
60d3c1e14bSEdwin Groothuis #define	ENV_OBJECTS_FMT2	2
61d3c1e14bSEdwin Groothuis #define	ENV_OBJECTS_PROGNAME	3
62d3c1e14bSEdwin Groothuis #define	ENV_OBJECTS_ALL		4
63d3c1e14bSEdwin Groothuis #define	ENV_LAST		5
64d3c1e14bSEdwin Groothuis 
65d3c1e14bSEdwin Groothuis const char	*envdef[ENV_LAST] = {
66d3c1e14bSEdwin Groothuis 	"LD_TRACE_LOADED_OBJECTS",
67d3c1e14bSEdwin Groothuis 	"LD_TRACE_LOADED_OBJECTS_FMT1",
68d3c1e14bSEdwin Groothuis 	"LD_TRACE_LOADED_OBJECTS_FMT2",
69d3c1e14bSEdwin Groothuis 	"LD_TRACE_LOADED_OBJECTS_PROGNAME",
70d3c1e14bSEdwin Groothuis 	"LD_TRACE_LOADED_OBJECTS_ALL",
71d3c1e14bSEdwin Groothuis };
72b9ae52e3SPaul Richards 
73b9ae52e3SPaul Richards int
74a53809fdSMark Murray main(int argc, char *argv[])
75b9ae52e3SPaul Richards {
76a0d476a9SEdwin Groothuis 	char *fmt1, *fmt2;
77a0d476a9SEdwin Groothuis 	int rval, c, aflag, vflag;
78b9ae52e3SPaul Richards 
7920249943SDavid E. O'Brien 	aflag = vflag = 0;
80a0d476a9SEdwin Groothuis 	fmt1 = fmt2 = NULL;
8120249943SDavid E. O'Brien 
82a0d476a9SEdwin Groothuis 	while ((c = getopt(argc, argv, "af:v")) != -1) {
83b9ae52e3SPaul Richards 		switch (c) {
8420249943SDavid E. O'Brien 		case 'a':
8520249943SDavid E. O'Brien 			aflag++;
8620249943SDavid E. O'Brien 			break;
87d138df61SPeter Wemm 		case 'f':
88a0d476a9SEdwin Groothuis 			if (fmt1 != NULL) {
89a0d476a9SEdwin Groothuis 				if (fmt2 != NULL)
903e762626SPhilippe Charnier 					errx(1, "too many formats");
91d138df61SPeter Wemm 				fmt2 = optarg;
92d138df61SPeter Wemm 			} else
93d138df61SPeter Wemm 				fmt1 = optarg;
94d138df61SPeter Wemm 			break;
95a0d476a9SEdwin Groothuis 		case 'v':
96a0d476a9SEdwin Groothuis 			vflag++;
97a0d476a9SEdwin Groothuis 			break;
98b9ae52e3SPaul Richards 		default:
99b9ae52e3SPaul Richards 			usage();
100699e1b82SRich Murphey 			/* NOTREACHED */
101b9ae52e3SPaul Richards 		}
102b9ae52e3SPaul Richards 	}
103b9ae52e3SPaul Richards 	argc -= optind;
104b9ae52e3SPaul Richards 	argv += optind;
105b9ae52e3SPaul Richards 
106a0d476a9SEdwin Groothuis 	if (vflag && fmt1 != NULL)
1079731d137SPeter Wemm 		errx(1, "-v may not be used with -f");
1089731d137SPeter Wemm 
109b9ae52e3SPaul Richards 	if (argc <= 0) {
110b9ae52e3SPaul Richards 		usage();
111699e1b82SRich Murphey 		/* NOTREACHED */
112b9ae52e3SPaul Richards 	}
113b9ae52e3SPaul Richards 
11497db68b6SDoug Rabson #ifdef __i386__
1159731d137SPeter Wemm 	if (vflag) {
1169731d137SPeter Wemm 		for (c = 0; c < argc; c++)
1179731d137SPeter Wemm 			dump_file(argv[c]);
1189731d137SPeter Wemm 		exit(error_count == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
1199731d137SPeter Wemm 	}
12097db68b6SDoug Rabson #endif
1219731d137SPeter Wemm 
122699e1b82SRich Murphey 	rval = 0;
123e2daa140SJohn Polstra 	for (; argc > 0; argc--, argv++) {
124d3c1e14bSEdwin Groothuis 		int fd, status, is_shlib, rv, type;
125d3c1e14bSEdwin Groothuis 		const char **env;
126d3c1e14bSEdwin Groothuis 
127d3c1e14bSEdwin Groothuis 		env = envdef;	/* Temporary placeholder */
128b9ae52e3SPaul Richards 
129b9ae52e3SPaul Richards 		if ((fd = open(*argv, O_RDONLY, 0)) < 0) {
130699e1b82SRich Murphey 			warn("%s", *argv);
131b9ae52e3SPaul Richards 			rval |= 1;
132b9ae52e3SPaul Richards 			continue;
133b9ae52e3SPaul Richards 		}
134d3c1e14bSEdwin Groothuis 		rv = is_executable(*argv, fd, &is_shlib, &type);
135a0d476a9SEdwin Groothuis 		close(fd);
136d3c1e14bSEdwin Groothuis 		if (rv == 0) {
137c474c6d3SDoug Rabson 			rval |= 1;
138c474c6d3SDoug Rabson 			continue;
139c474c6d3SDoug Rabson 		}
140c474c6d3SDoug Rabson 
141d3c1e14bSEdwin Groothuis 		/* ld.so magic */
142d3c1e14bSEdwin Groothuis 		setenv(env[ENV_OBJECTS], "yes", 1);
143d3c1e14bSEdwin Groothuis 		if (fmt1 != NULL)
144d3c1e14bSEdwin Groothuis 			setenv(env[ENV_OBJECTS_FMT1], fmt1, 1);
145d3c1e14bSEdwin Groothuis 		if (fmt2 != NULL)
146d3c1e14bSEdwin Groothuis 			setenv(env[ENV_OBJECTS_FMT2], fmt2, 1);
147a0d476a9SEdwin Groothuis 
148d3c1e14bSEdwin Groothuis 		setenv(env[ENV_OBJECTS_PROGNAME], *argv, 1);
149a0d476a9SEdwin Groothuis 		if (aflag)
150d3c1e14bSEdwin Groothuis 			setenv(env[ENV_OBJECTS_ALL], "1", 1);
15120249943SDavid E. O'Brien 		else if (fmt1 == NULL && fmt2 == NULL)
152d138df61SPeter Wemm 			/* Default formats */
153b9ae52e3SPaul Richards 			printf("%s:\n", *argv);
15409e3d49dSJordan K. Hubbard 		fflush(stdout);
155b9ae52e3SPaul Richards 
156b9ae52e3SPaul Richards 		switch (fork()) {
157b9ae52e3SPaul Richards 		case -1:
158699e1b82SRich Murphey 			err(1, "fork");
159b9ae52e3SPaul Richards 			break;
160b9ae52e3SPaul Richards 		default:
161699e1b82SRich Murphey 			if (wait(&status) <= 0) {
162699e1b82SRich Murphey 				warn("wait");
163699e1b82SRich Murphey 				rval |= 1;
164699e1b82SRich Murphey 			} else if (WIFSIGNALED(status)) {
165a0d476a9SEdwin Groothuis 				fprintf(stderr, "%s: signal %d\n", *argv,
166a0d476a9SEdwin Groothuis 				    WTERMSIG(status));
167b9ae52e3SPaul Richards 				rval |= 1;
168b9ae52e3SPaul Richards 			} else if (WIFEXITED(status) && WEXITSTATUS(status)) {
169a0d476a9SEdwin Groothuis 				fprintf(stderr, "%s: exit status %d\n", *argv,
170a0d476a9SEdwin Groothuis 				    WEXITSTATUS(status));
171b9ae52e3SPaul Richards 				rval |= 1;
172b9ae52e3SPaul Richards 			}
173b9ae52e3SPaul Richards 			break;
174b9ae52e3SPaul Richards 		case 0:
175d1cf9ea2SMaxim Sobolev 			if (is_shlib == 0) {
176fc41545eSMaxim Sobolev 				execl(*argv, *argv, (char *)NULL);
1773e762626SPhilippe Charnier 				warn("%s", *argv);
178d1cf9ea2SMaxim Sobolev 			} else {
179d1cf9ea2SMaxim Sobolev 				dlopen(*argv, RTLD_TRACE);
180d1cf9ea2SMaxim Sobolev 				warnx("%s: %s", *argv, dlerror());
181c6de4ce7SMaxim Sobolev 			}
182b9ae52e3SPaul Richards 			_exit(1);
183b9ae52e3SPaul Richards 		}
184b9ae52e3SPaul Richards 	}
185b9ae52e3SPaul Richards 
186b9ae52e3SPaul Richards 	return rval;
187b9ae52e3SPaul Richards }
188d3c1e14bSEdwin Groothuis 
189d3c1e14bSEdwin Groothuis static void
190d3c1e14bSEdwin Groothuis usage(void)
191d3c1e14bSEdwin Groothuis {
192d3c1e14bSEdwin Groothuis 
193d3c1e14bSEdwin Groothuis 	fprintf(stderr, "usage: ldd [-a] [-v] [-f format] program ...\n");
194d3c1e14bSEdwin Groothuis 	exit(1);
195d3c1e14bSEdwin Groothuis }
196d3c1e14bSEdwin Groothuis 
197d3c1e14bSEdwin Groothuis static int
198d3c1e14bSEdwin Groothuis is_executable(const char *fname, int fd, int *is_shlib, int *type)
199d3c1e14bSEdwin Groothuis {
200d3c1e14bSEdwin Groothuis 	union {
201d3c1e14bSEdwin Groothuis 		struct exec aout;
202d3c1e14bSEdwin Groothuis 		Elf_Ehdr elf;
203d3c1e14bSEdwin Groothuis 	} hdr;
204d3c1e14bSEdwin Groothuis 	int n;
205d3c1e14bSEdwin Groothuis 
206d3c1e14bSEdwin Groothuis 	*is_shlib = 0;
207d3c1e14bSEdwin Groothuis 	*type = TYPE_UNKNOWN;
208d3c1e14bSEdwin Groothuis 
209d3c1e14bSEdwin Groothuis 	if ((n = read(fd, &hdr, sizeof(hdr))) == -1) {
210d3c1e14bSEdwin Groothuis 		warn("%s: can't read program header", fname);
211d3c1e14bSEdwin Groothuis 		return (0);
212d3c1e14bSEdwin Groothuis 	}
213d3c1e14bSEdwin Groothuis 
214d3c1e14bSEdwin Groothuis 	if ((size_t)n >= sizeof(hdr.aout) && !N_BADMAG(hdr.aout)) {
215d3c1e14bSEdwin Groothuis 		/* a.out file */
216d3c1e14bSEdwin Groothuis 		if ((N_GETFLAG(hdr.aout) & EX_DPMASK) != EX_DYNAMIC
217d3c1e14bSEdwin Groothuis #if 1 /* Compatibility */
218d3c1e14bSEdwin Groothuis 		    || hdr.aout.a_entry < __LDPGSZ
219d3c1e14bSEdwin Groothuis #endif
220d3c1e14bSEdwin Groothuis 			) {
221d3c1e14bSEdwin Groothuis 			warnx("%s: not a dynamic executable", fname);
222d3c1e14bSEdwin Groothuis 			return (0);
223d3c1e14bSEdwin Groothuis 		}
224d3c1e14bSEdwin Groothuis 		*type = TYPE_AOUT;
225d3c1e14bSEdwin Groothuis 		return (1);
226d3c1e14bSEdwin Groothuis 	}
227d3c1e14bSEdwin Groothuis 
228d3c1e14bSEdwin Groothuis 	if ((size_t)n >= sizeof(hdr.elf) && IS_ELF(hdr.elf) &&
229d3c1e14bSEdwin Groothuis 	    hdr.elf.e_ident[EI_CLASS] == ELF_TARG_CLASS) {
230d3c1e14bSEdwin Groothuis 		/* Handle default ELF objects on this architecture */
231d3c1e14bSEdwin Groothuis 		Elf_Phdr phdr;
232d3c1e14bSEdwin Groothuis 		int dynamic, i;
233d3c1e14bSEdwin Groothuis 
234d3c1e14bSEdwin Groothuis 		dynamic = 0;
235d3c1e14bSEdwin Groothuis 		*type = TYPE_ELF;
236d3c1e14bSEdwin Groothuis 
237d3c1e14bSEdwin Groothuis 		if (lseek(fd, hdr.elf.e_phoff, SEEK_SET) == -1) {
238d3c1e14bSEdwin Groothuis 			warnx("%s: header too short", fname);
239d3c1e14bSEdwin Groothuis 			return (0);
240d3c1e14bSEdwin Groothuis 		}
241d3c1e14bSEdwin Groothuis 		for (i = 0; i < hdr.elf.e_phnum; i++) {
242d3c1e14bSEdwin Groothuis 			if (read(fd, &phdr, hdr.elf.e_phentsize)
243d3c1e14bSEdwin Groothuis 			   != sizeof(phdr)) {
244d3c1e14bSEdwin Groothuis 				warnx("%s: can't read program header", fname);
245d3c1e14bSEdwin Groothuis 				return (0);
246d3c1e14bSEdwin Groothuis 			}
247d3c1e14bSEdwin Groothuis 			if (phdr.p_type == PT_DYNAMIC) {
248d3c1e14bSEdwin Groothuis 				dynamic = 1;
249d3c1e14bSEdwin Groothuis 				break;
250d3c1e14bSEdwin Groothuis 			}
251d3c1e14bSEdwin Groothuis 		}
252d3c1e14bSEdwin Groothuis 
253d3c1e14bSEdwin Groothuis 		if (!dynamic) {
254d3c1e14bSEdwin Groothuis 			warnx("%s: not a dynamic ELF executable", fname);
255d3c1e14bSEdwin Groothuis 			return (0);
256d3c1e14bSEdwin Groothuis 		}
257d3c1e14bSEdwin Groothuis 		if (hdr.elf.e_type == ET_DYN) {
258d3c1e14bSEdwin Groothuis 			if (hdr.elf.e_ident[EI_OSABI] & ELFOSABI_FREEBSD) {
259d3c1e14bSEdwin Groothuis 				*is_shlib = 1;
260d3c1e14bSEdwin Groothuis 				return (1);
261d3c1e14bSEdwin Groothuis 			}
262d3c1e14bSEdwin Groothuis 			warnx("%s: not a FreeBSD ELF shared object", fname);
263d3c1e14bSEdwin Groothuis 			return (0);
264d3c1e14bSEdwin Groothuis 		}
265d3c1e14bSEdwin Groothuis 
266d3c1e14bSEdwin Groothuis 		return (1);
267d3c1e14bSEdwin Groothuis 	}
268d3c1e14bSEdwin Groothuis 
269d3c1e14bSEdwin Groothuis 	warnx("%s: not a dynamic executable", fname);
270d3c1e14bSEdwin Groothuis 	return (0);
271d3c1e14bSEdwin Groothuis }
272