xref: /freebsd/usr.bin/ldd/ldd.c (revision 3e7626264d8ced44e0a0b379f5dacf9152348729)
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 
313e762626SPhilippe Charnier #ifndef lint
323e762626SPhilippe Charnier static const char rcsid[] =
333e762626SPhilippe Charnier   "$FreeBSD$";
343e762626SPhilippe Charnier #endif /* not lint */
353e762626SPhilippe Charnier 
36b9ae52e3SPaul Richards #include <sys/wait.h>
37b9ae52e3SPaul Richards #include <a.out.h>
38c474c6d3SDoug Rabson #include <elf.h>
39699e1b82SRich Murphey #include <err.h>
40699e1b82SRich Murphey #include <fcntl.h>
41699e1b82SRich Murphey #include <stdio.h>
42699e1b82SRich Murphey #include <stdlib.h>
43699e1b82SRich Murphey #include <unistd.h>
44b9ae52e3SPaul Richards 
45170fa4e8SJohn Polstra extern void	dump_file __P((const char *));
469731d137SPeter Wemm extern int	error_count;
479731d137SPeter Wemm 
48b9ae52e3SPaul Richards void
49b9ae52e3SPaul Richards usage()
50b9ae52e3SPaul Richards {
5145f4c7f9SBruce Evans 	fprintf(stderr, "usage: ldd [-v] [-f format] program ...\n");
52699e1b82SRich Murphey 	exit(1);
53b9ae52e3SPaul Richards }
54b9ae52e3SPaul Richards 
55b9ae52e3SPaul Richards int
56b9ae52e3SPaul Richards main(argc, argv)
57b9ae52e3SPaul Richards int	argc;
58b9ae52e3SPaul Richards char	*argv[];
59b9ae52e3SPaul Richards {
60d138df61SPeter Wemm 	char		*fmt1 = NULL, *fmt2 = NULL;
61699e1b82SRich Murphey 	int		rval;
62b9ae52e3SPaul Richards 	int		c;
63fecaa127SPeter Wemm 	int		vflag = 0;
64b9ae52e3SPaul Richards 
6562f882d6SWarner Losh 	while ((c = getopt(argc, argv, "vf:")) != -1) {
66b9ae52e3SPaul Richards 		switch (c) {
679731d137SPeter Wemm 		case 'v':
689731d137SPeter Wemm 			vflag++;
699731d137SPeter Wemm 			break;
70d138df61SPeter Wemm 		case 'f':
71d138df61SPeter Wemm 			if (fmt1) {
72d138df61SPeter Wemm 				if (fmt2)
733e762626SPhilippe Charnier 					errx(1, "too many formats");
74d138df61SPeter Wemm 				fmt2 = optarg;
75d138df61SPeter Wemm 			} else
76d138df61SPeter Wemm 				fmt1 = optarg;
77d138df61SPeter Wemm 			break;
78b9ae52e3SPaul Richards 		default:
79b9ae52e3SPaul Richards 			usage();
80699e1b82SRich Murphey 			/*NOTREACHED*/
81b9ae52e3SPaul Richards 		}
82b9ae52e3SPaul Richards 	}
83b9ae52e3SPaul Richards 	argc -= optind;
84b9ae52e3SPaul Richards 	argv += optind;
85b9ae52e3SPaul Richards 
869731d137SPeter Wemm 	if (vflag && fmt1)
879731d137SPeter Wemm 		errx(1, "-v may not be used with -f");
889731d137SPeter Wemm 
89b9ae52e3SPaul Richards 	if (argc <= 0) {
90b9ae52e3SPaul Richards 		usage();
91699e1b82SRich Murphey 		/*NOTREACHED*/
92b9ae52e3SPaul Richards 	}
93b9ae52e3SPaul Richards 
9497db68b6SDoug Rabson #ifdef __i386__
959731d137SPeter Wemm 	if (vflag) {
969731d137SPeter Wemm 		for (c = 0; c < argc; c++)
979731d137SPeter Wemm 			dump_file(argv[c]);
989731d137SPeter Wemm 		exit(error_count == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
999731d137SPeter Wemm 	}
10097db68b6SDoug Rabson #endif
1019731d137SPeter Wemm 
102b9ae52e3SPaul Richards 	/* ld.so magic */
10318c0f29eSJohn Polstra 	setenv("LD_TRACE_LOADED_OBJECTS", "1", 1);
104d138df61SPeter Wemm 	if (fmt1)
105d138df61SPeter Wemm 		setenv("LD_TRACE_LOADED_OBJECTS_FMT1", fmt1, 1);
106d138df61SPeter Wemm 	if (fmt2)
107d138df61SPeter Wemm 		setenv("LD_TRACE_LOADED_OBJECTS_FMT2", fmt2, 1);
108b9ae52e3SPaul Richards 
109699e1b82SRich Murphey 	rval = 0;
110e2daa140SJohn Polstra 	for ( ;  argc > 0;  argc--, argv++) {
111b9ae52e3SPaul Richards 		int	fd;
112e2daa140SJohn Polstra 		union {
113e2daa140SJohn Polstra 			struct exec aout;
11497db68b6SDoug Rabson 			Elf_Ehdr elf;
115e2daa140SJohn Polstra 		} hdr;
116e2daa140SJohn Polstra 		int	n;
117b9ae52e3SPaul Richards 		int	status;
118e2daa140SJohn Polstra 		int	file_ok;
119b9ae52e3SPaul Richards 
120b9ae52e3SPaul Richards 		if ((fd = open(*argv, O_RDONLY, 0)) < 0) {
121699e1b82SRich Murphey 			warn("%s", *argv);
122b9ae52e3SPaul Richards 			rval |= 1;
123b9ae52e3SPaul Richards 			continue;
124b9ae52e3SPaul Richards 		}
125e2daa140SJohn Polstra 		if ((n = read(fd, &hdr, sizeof hdr)) == -1) {
126e2daa140SJohn Polstra 			warn("%s: can't read program header", *argv);
127c474c6d3SDoug Rabson 			(void)close(fd);
128c474c6d3SDoug Rabson 			rval |= 1;
129c474c6d3SDoug Rabson 			continue;
130c474c6d3SDoug Rabson 		}
131c474c6d3SDoug Rabson 
132e2daa140SJohn Polstra 		file_ok = 1;
133e2daa140SJohn Polstra 		if (n >= sizeof hdr.aout && !N_BADMAG(hdr.aout)) {
134c474c6d3SDoug Rabson 			/* a.out file */
135e2daa140SJohn Polstra 			if ((N_GETFLAG(hdr.aout) & EX_DPMASK) != EX_DYNAMIC
13661f9ce8dSNate Williams #if 1 /* Compatibility */
137e2daa140SJohn Polstra 			    || hdr.aout.a_entry < __LDPGSZ
13861f9ce8dSNate Williams #endif
13961f9ce8dSNate Williams 				) {
140699e1b82SRich Murphey 				warnx("%s: not a dynamic executable", *argv);
141e2daa140SJohn Polstra 				file_ok = 0;
142b9ae52e3SPaul Richards 			}
143e2daa140SJohn Polstra 		} else if (n >= sizeof hdr.elf && IS_ELF(hdr.elf)) {
14497db68b6SDoug Rabson 			Elf_Ehdr ehdr;
14597db68b6SDoug Rabson 			Elf_Phdr phdr;
146c474c6d3SDoug Rabson 			int dynamic = 0, i;
147c474c6d3SDoug Rabson 
148c474c6d3SDoug Rabson 			lseek(fd, 0, SEEK_SET);
149c474c6d3SDoug Rabson 			if (read(fd, &ehdr, sizeof ehdr) != sizeof ehdr) {
150c474c6d3SDoug Rabson 				warnx("%s: can't read program header", *argv);
151e2daa140SJohn Polstra 				file_ok = 0;
152c474c6d3SDoug Rabson 			}
153c474c6d3SDoug Rabson 			lseek(fd, 0, ehdr.e_phoff);
154c474c6d3SDoug Rabson 			for (i = 0; i < ehdr.e_phnum; i++) {
155c474c6d3SDoug Rabson 				if (read(fd, &phdr, ehdr.e_phentsize)
156c474c6d3SDoug Rabson 				   != sizeof phdr) {
157e2daa140SJohn Polstra 					warnx("%s: can't read program header",
158e2daa140SJohn Polstra 					    *argv);
159e2daa140SJohn Polstra 					file_ok = 0;
160c474c6d3SDoug Rabson 				}
161c474c6d3SDoug Rabson 				if (phdr.p_type == PT_DYNAMIC)
162c474c6d3SDoug Rabson 					dynamic = 1;
163c474c6d3SDoug Rabson 			}
164c474c6d3SDoug Rabson 			if (!dynamic) {
165c474c6d3SDoug Rabson 				warnx("%s: not a dynamic executable", *argv);
166e2daa140SJohn Polstra 				file_ok = 0;
167e2daa140SJohn Polstra 			}
168e2daa140SJohn Polstra 		} else {
169e2daa140SJohn Polstra 			warnx("%s: not a dynamic executable", *argv);
170e2daa140SJohn Polstra 			file_ok = 0;
171e2daa140SJohn Polstra 		}
172c474c6d3SDoug Rabson 		(void)close(fd);
173e2daa140SJohn Polstra 		if (!file_ok) {
174c474c6d3SDoug Rabson 			rval |= 1;
175c474c6d3SDoug Rabson 			continue;
176c474c6d3SDoug Rabson 		}
177b9ae52e3SPaul Richards 
178d138df61SPeter Wemm 		setenv("LD_TRACE_LOADED_OBJECTS_PROGNAME", *argv, 1);
179d138df61SPeter Wemm 		if (fmt1 == NULL && fmt2 == NULL)
180d138df61SPeter Wemm 			/* Default formats */
181b9ae52e3SPaul Richards 			printf("%s:\n", *argv);
182d138df61SPeter Wemm 
18309e3d49dSJordan K. Hubbard 		fflush(stdout);
184b9ae52e3SPaul Richards 
185b9ae52e3SPaul Richards 		switch (fork()) {
186b9ae52e3SPaul Richards 		case -1:
187699e1b82SRich Murphey 			err(1, "fork");
188b9ae52e3SPaul Richards 			break;
189b9ae52e3SPaul Richards 		default:
190699e1b82SRich Murphey 			if (wait(&status) <= 0) {
191699e1b82SRich Murphey 				warn("wait");
192699e1b82SRich Murphey 				rval |= 1;
193699e1b82SRich Murphey 			} else if (WIFSIGNALED(status)) {
194b9ae52e3SPaul Richards 				fprintf(stderr, "%s: signal %d\n",
195b9ae52e3SPaul Richards 						*argv, WTERMSIG(status));
196b9ae52e3SPaul Richards 				rval |= 1;
197b9ae52e3SPaul Richards 			} else if (WIFEXITED(status) && WEXITSTATUS(status)) {
198b9ae52e3SPaul Richards 				fprintf(stderr, "%s: exit status %d\n",
199b9ae52e3SPaul Richards 						*argv, WEXITSTATUS(status));
200b9ae52e3SPaul Richards 				rval |= 1;
201b9ae52e3SPaul Richards 			}
202b9ae52e3SPaul Richards 			break;
203b9ae52e3SPaul Richards 		case 0:
204699e1b82SRich Murphey 			rval |= execl(*argv, *argv, NULL) != 0;
2053e762626SPhilippe Charnier 			warn("%s", *argv);
206b9ae52e3SPaul Richards 			_exit(1);
207b9ae52e3SPaul Richards 		}
208b9ae52e3SPaul Richards 	}
209b9ae52e3SPaul Richards 
210b9ae52e3SPaul Richards 	return rval;
211b9ae52e3SPaul Richards }
212