ldd.c revision 39354
1178355Ssam/*
2178355Ssam * Copyright (c) 1993 Paul Kranenburg
3178355Ssam * All rights reserved.
4208060Sdougb *
5178355Ssam * Redistribution and use in source and binary forms, with or without
6178355Ssam * modification, are permitted provided that the following conditions
7178355Ssam * are met:
8178355Ssam * 1. Redistributions of source code must retain the above copyright
9178355Ssam *    notice, this list of conditions and the following disclaimer.
10178355Ssam * 2. Redistributions in binary form must reproduce the above copyright
11178355Ssam *    notice, this list of conditions and the following disclaimer in the
12178355Ssam *    documentation and/or other materials provided with the distribution.
13208060Sdougb * 3. All advertising materials mentioning features or use of this software
14178355Ssam *    must display the following acknowledgement:
15178355Ssam *      This product includes software developed by Paul Kranenburg.
16178355Ssam * 4. The name of the author may not be used to endorse or promote products
17178355Ssam *    derived from this software without specific prior written permission
18178355Ssam *
19178355Ssam * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20178355Ssam * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21178355Ssam * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22178355Ssam * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23178355Ssam * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24208060Sdougb * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25178355Ssam * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26178355Ssam * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27178355Ssam * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28178355Ssam * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29178355Ssam *
30178355Ssam *	$Id: ldd.c,v 1.16 1998/08/30 18:30:59 jdp Exp $
31178355Ssam */
32178355Ssam
33178355Ssam#include <sys/types.h>
34178355Ssam#include <sys/stat.h>
35178355Ssam#include <sys/file.h>
36178355Ssam#include <sys/time.h>
37178355Ssam#include <sys/resource.h>
38178355Ssam#include <sys/wait.h>
39178355Ssam#include <a.out.h>
40178355Ssam#include <elf.h>
41178355Ssam#include <err.h>
42186106Ssam#include <fcntl.h>
43178355Ssam#include <stdio.h>
44178355Ssam#include <stdlib.h>
45178355Ssam#include <string.h>
46178355Ssam#include <unistd.h>
47178355Ssam
48178355Ssamextern void	dump_file __P((const char *));
49178355Ssamextern int	error_count;
50178355Ssam
51178355Ssamvoid
52178355Ssamusage()
53178355Ssam{
54178355Ssam	fprintf(stderr, "usage: ldd [-v] [-f format] program ...\n");
55178355Ssam	exit(1);
56178355Ssam}
57178355Ssam
58178355Ssamint
59178355Ssammain(argc, argv)
60178355Ssamint	argc;
61178355Ssamchar	*argv[];
62178355Ssam{
63178355Ssam	char		*fmt1 = NULL, *fmt2 = NULL;
64178355Ssam	int		rval;
65178355Ssam	int		c;
66178355Ssam	int		vflag = 0;
67178355Ssam
68178355Ssam	while ((c = getopt(argc, argv, "vf:")) != EOF) {
69178355Ssam		switch (c) {
70178355Ssam		case 'v':
71178355Ssam			vflag++;
72178355Ssam			break;
73178355Ssam		case 'f':
74178355Ssam			if (fmt1) {
75178355Ssam				if (fmt2)
76178355Ssam					errx(1, "Too many formats");
77178355Ssam				fmt2 = optarg;
78178355Ssam			} else
79178355Ssam				fmt1 = optarg;
80178355Ssam			break;
81178355Ssam		default:
82178355Ssam			usage();
83178355Ssam			/*NOTREACHED*/
84178355Ssam		}
85178355Ssam	}
86223497Sadrian	argc -= optind;
87178355Ssam	argv += optind;
88178355Ssam
89178355Ssam	if (vflag && fmt1)
90178355Ssam		errx(1, "-v may not be used with -f");
91178355Ssam
92178355Ssam	if (argc <= 0) {
93178355Ssam		usage();
94178355Ssam		/*NOTREACHED*/
95178355Ssam	}
96178355Ssam
97178355Ssam#ifdef __i386__
98178355Ssam	if (vflag) {
99223498Sadrian		for (c = 0; c < argc; c++)
100178355Ssam			dump_file(argv[c]);
101178355Ssam		exit(error_count == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
102178355Ssam	}
103178355Ssam#endif
104178355Ssam
105178355Ssam	/* ld.so magic */
106178355Ssam	setenv("LD_TRACE_LOADED_OBJECTS", "1", 1);
107178355Ssam	if (fmt1)
108178355Ssam		setenv("LD_TRACE_LOADED_OBJECTS_FMT1", fmt1, 1);
109223498Sadrian	if (fmt2)
110178355Ssam		setenv("LD_TRACE_LOADED_OBJECTS_FMT2", fmt2, 1);
111178355Ssam
112178355Ssam	rval = 0;
113178355Ssam	for ( ;  argc > 0;  argc--, argv++) {
114178355Ssam		int	fd;
115178355Ssam		union {
116178355Ssam			struct exec aout;
117178355Ssam			Elf_Ehdr elf;
118178355Ssam		} hdr;
119178355Ssam		int	n;
120178355Ssam		int	status;
121178355Ssam		int	file_ok;
122178355Ssam
123178355Ssam		if ((fd = open(*argv, O_RDONLY, 0)) < 0) {
124178355Ssam			warn("%s", *argv);
125178355Ssam			rval |= 1;
126178355Ssam			continue;
127178355Ssam		}
128178355Ssam		if ((n = read(fd, &hdr, sizeof hdr)) == -1) {
129178355Ssam			warn("%s: can't read program header", *argv);
130178355Ssam			(void)close(fd);
131178355Ssam			rval |= 1;
132178355Ssam			continue;
133178355Ssam		}
134178355Ssam
135178355Ssam		file_ok = 1;
136178355Ssam		if (n >= sizeof hdr.aout && !N_BADMAG(hdr.aout)) {
137178355Ssam			/* a.out file */
138178355Ssam			if ((N_GETFLAG(hdr.aout) & EX_DPMASK) != EX_DYNAMIC
139178355Ssam#if 1 /* Compatibility */
140178355Ssam			    || hdr.aout.a_entry < __LDPGSZ
141223496Sadrian#endif
142223564Sadrian				) {
143223496Sadrian				warnx("%s: not a dynamic executable", *argv);
144223496Sadrian				file_ok = 0;
145223496Sadrian			}
146223496Sadrian		} else if (n >= sizeof hdr.elf && IS_ELF(hdr.elf)) {
147223563Sadrian			Elf_Ehdr ehdr;
148223564Sadrian			Elf_Phdr phdr;
149223563Sadrian			int dynamic = 0, i;
150223563Sadrian
151223563Sadrian			lseek(fd, 0, SEEK_SET);
152223563Sadrian			if (read(fd, &ehdr, sizeof ehdr) != sizeof ehdr) {
153223563Sadrian				warnx("%s: can't read program header", *argv);
154223564Sadrian				file_ok = 0;
155223563Sadrian			}
156223563Sadrian			lseek(fd, 0, ehdr.e_phoff);
157223563Sadrian			for (i = 0; i < ehdr.e_phnum; i++) {
158223563Sadrian				if (read(fd, &phdr, ehdr.e_phentsize)
159178355Ssam				   != sizeof phdr) {
160178355Ssam					warnx("%s: can't read program header",
161178355Ssam					    *argv);
162178355Ssam					file_ok = 0;
163178355Ssam				}
164178355Ssam				if (phdr.p_type == PT_DYNAMIC)
165178355Ssam					dynamic = 1;
166178355Ssam			}
167178355Ssam			if (!dynamic) {
168178355Ssam				warnx("%s: not a dynamic executable", *argv);
169178355Ssam				file_ok = 0;
170178355Ssam			}
171178355Ssam		} else {
172178355Ssam			warnx("%s: not a dynamic executable", *argv);
173178355Ssam			file_ok = 0;
174178355Ssam		}
175178355Ssam		(void)close(fd);
176178355Ssam		if (!file_ok) {
177178355Ssam			rval |= 1;
178178355Ssam			continue;
179178355Ssam		}
180178355Ssam
181178355Ssam		setenv("LD_TRACE_LOADED_OBJECTS_PROGNAME", *argv, 1);
182178355Ssam		if (fmt1 == NULL && fmt2 == NULL)
183178355Ssam			/* Default formats */
184178355Ssam			printf("%s:\n", *argv);
185178355Ssam
186178355Ssam		fflush(stdout);
187178355Ssam
188178355Ssam		switch (fork()) {
189178355Ssam		case -1:
190178355Ssam			err(1, "fork");
191178355Ssam			break;
192178355Ssam		default:
193178355Ssam			if (wait(&status) <= 0) {
194178355Ssam				warn("wait");
195178355Ssam				rval |= 1;
196178355Ssam			} else if (WIFSIGNALED(status)) {
197223496Sadrian				fprintf(stderr, "%s: signal %d\n",
198223564Sadrian						*argv, WTERMSIG(status));
199223496Sadrian				rval |= 1;
200223496Sadrian			} else if (WIFEXITED(status) && WEXITSTATUS(status)) {
201223496Sadrian				fprintf(stderr, "%s: exit status %d\n",
202223496Sadrian						*argv, WEXITSTATUS(status));
203223496Sadrian				rval |= 1;
204223496Sadrian			}
205223564Sadrian			break;
206223496Sadrian		case 0:
207223496Sadrian			rval |= execl(*argv, *argv, NULL) != 0;
208223496Sadrian			perror(*argv);
209223496Sadrian			_exit(1);
210223496Sadrian		}
211223563Sadrian	}
212223564Sadrian
213223563Sadrian	return rval;
214223563Sadrian}
215223563Sadrian