ldd.c revision 105439
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 105439 2002-10-19 10:18:29Z sobomax $");
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>
431741Srich#include <fcntl.h>
441741Srich#include <stdio.h>
451741Srich#include <stdlib.h>
461741Srich#include <unistd.h>
47696Spaul
4895648Smarkm#include "extern.h"
4918600Speter
5095648Smarkmstatic void
5195648Smarkmusage(void)
52696Spaul{
5390755Sobrien	fprintf(stderr, "usage: ldd [-a] [-v] [-f format] program ...\n");
541741Srich	exit(1);
55696Spaul}
56696Spaul
57696Spaulint
5895648Smarkmmain(int argc, char *argv[])
59696Spaul{
6018598Speter	char		*fmt1 = NULL, *fmt2 = NULL;
611741Srich	int		rval;
62696Spaul	int		c;
6390755Sobrien	int		aflag, vflag;
64696Spaul
6590755Sobrien	aflag = vflag = 0;
6690755Sobrien
6790755Sobrien	while ((c = getopt(argc, argv, "avf:")) != -1) {
68696Spaul		switch (c) {
6990755Sobrien		case 'a':
7090755Sobrien			aflag++;
7190755Sobrien			break;
7218600Speter		case 'v':
7318600Speter			vflag++;
7418600Speter			break;
7518598Speter		case 'f':
7618598Speter			if (fmt1) {
7718598Speter				if (fmt2)
7869827Scharnier					errx(1, "too many formats");
7918598Speter				fmt2 = optarg;
8018598Speter			} else
8118598Speter				fmt1 = optarg;
8218598Speter			break;
83696Spaul		default:
84696Spaul			usage();
851741Srich			/*NOTREACHED*/
86696Spaul		}
87696Spaul	}
88696Spaul	argc -= optind;
89696Spaul	argv += optind;
90696Spaul
9118600Speter	if (vflag && fmt1)
9218600Speter		errx(1, "-v may not be used with -f");
9318600Speter
94696Spaul	if (argc <= 0) {
95696Spaul		usage();
961741Srich		/*NOTREACHED*/
97696Spaul	}
98696Spaul
9939354Sdfr#ifdef __i386__
10018600Speter	if (vflag) {
10118600Speter		for (c = 0; c < argc; c++)
10218600Speter			dump_file(argv[c]);
10318600Speter		exit(error_count == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
10418600Speter	}
10539354Sdfr#endif
10618600Speter
107696Spaul	/* ld.so magic */
10890755Sobrien	setenv("LD_TRACE_LOADED_OBJECTS", "yes", 1);
10918598Speter	if (fmt1)
11018598Speter		setenv("LD_TRACE_LOADED_OBJECTS_FMT1", fmt1, 1);
11118598Speter	if (fmt2)
11218598Speter		setenv("LD_TRACE_LOADED_OBJECTS_FMT2", fmt2, 1);
113696Spaul
1141741Srich	rval = 0;
11538648Sjdp	for ( ;  argc > 0;  argc--, argv++) {
116696Spaul		int	fd;
11738648Sjdp		union {
11838648Sjdp			struct exec aout;
11939354Sdfr			Elf_Ehdr elf;
12038648Sjdp		} hdr;
12138648Sjdp		int	n;
122696Spaul		int	status;
12338648Sjdp		int	file_ok;
12490172Ssobomax		int	is_shlib;
125696Spaul
126696Spaul		if ((fd = open(*argv, O_RDONLY, 0)) < 0) {
1271741Srich			warn("%s", *argv);
128696Spaul			rval |= 1;
129696Spaul			continue;
130696Spaul		}
13138648Sjdp		if ((n = read(fd, &hdr, sizeof hdr)) == -1) {
13238648Sjdp			warn("%s: can't read program header", *argv);
133696Spaul			(void)close(fd);
134696Spaul			rval |= 1;
135696Spaul			continue;
136696Spaul		}
13735575Sdfr
13838648Sjdp		file_ok = 1;
13990172Ssobomax		is_shlib = 0;
14095648Smarkm		if ((size_t)n >= sizeof hdr.aout && !N_BADMAG(hdr.aout)) {
14135575Sdfr			/* a.out file */
14238648Sjdp			if ((N_GETFLAG(hdr.aout) & EX_DPMASK) != EX_DYNAMIC
14335575Sdfr#if 1 /* Compatibility */
14438648Sjdp			    || hdr.aout.a_entry < __LDPGSZ
14535575Sdfr#endif
14635575Sdfr				) {
14735575Sdfr				warnx("%s: not a dynamic executable", *argv);
14838648Sjdp				file_ok = 0;
14935575Sdfr			}
15095648Smarkm		} else if ((size_t)n >= sizeof hdr.elf && IS_ELF(hdr.elf)) {
15139354Sdfr			Elf_Ehdr ehdr;
15239354Sdfr			Elf_Phdr phdr;
15335575Sdfr			int dynamic = 0, i;
15435575Sdfr
15570049Sache			if (lseek(fd, 0, SEEK_SET) == -1 ||
15670049Sache			    read(fd, &ehdr, sizeof ehdr) != sizeof ehdr ||
15770049Sache			    lseek(fd, ehdr.e_phoff, SEEK_SET) == -1
15870049Sache			   ) {
15935575Sdfr				warnx("%s: can't read program header", *argv);
16038648Sjdp				file_ok = 0;
16170049Sache			} else {
16270049Sache				for (i = 0; i < ehdr.e_phnum; i++) {
16370049Sache					if (read(fd, &phdr, ehdr.e_phentsize)
16470049Sache					   != sizeof phdr) {
16570049Sache						warnx("%s: can't read program header",
16670049Sache						    *argv);
16770049Sache						file_ok = 0;
16870049Sache						break;
16970049Sache					}
17070049Sache					if (phdr.p_type == PT_DYNAMIC)
17170049Sache						dynamic = 1;
17235575Sdfr				}
17335575Sdfr			}
17435575Sdfr			if (!dynamic) {
17535575Sdfr				warnx("%s: not a dynamic executable", *argv);
17638648Sjdp				file_ok = 0;
17790172Ssobomax			} else if (hdr.elf.e_type == ET_DYN) {
17890385Ssobomax				if (hdr.elf.e_ident[EI_OSABI] & ELFOSABI_FREEBSD) {
17990385Ssobomax					is_shlib = 1;
18090385Ssobomax				} else {
18190385Ssobomax					warnx("%s: not a FreeBSD ELF shared "
18290385Ssobomax					      "object", *argv);
18390385Ssobomax					file_ok = 0;
18490385Ssobomax				}
18535575Sdfr			}
18638648Sjdp		} else {
18738648Sjdp			warnx("%s: not a dynamic executable", *argv);
18838648Sjdp			file_ok = 0;
18935575Sdfr		}
190696Spaul		(void)close(fd);
19138648Sjdp		if (!file_ok) {
19238648Sjdp			rval |= 1;
19338648Sjdp			continue;
19438648Sjdp		}
195696Spaul
19618598Speter		setenv("LD_TRACE_LOADED_OBJECTS_PROGNAME", *argv, 1);
19790755Sobrien		if (aflag) setenv("LD_TRACE_LOADED_OBJECTS_ALL", "1", 1);
19890755Sobrien		else if (fmt1 == NULL && fmt2 == NULL)
19918598Speter			/* Default formats */
20018598Speter			printf("%s:\n", *argv);
20118598Speter
2021153Sjkh		fflush(stdout);
203696Spaul
204696Spaul		switch (fork()) {
205696Spaul		case -1:
2061741Srich			err(1, "fork");
207696Spaul			break;
208696Spaul		default:
2091741Srich			if (wait(&status) <= 0) {
2101741Srich				warn("wait");
2111741Srich				rval |= 1;
2121741Srich			} else if (WIFSIGNALED(status)) {
213696Spaul				fprintf(stderr, "%s: signal %d\n",
214696Spaul						*argv, WTERMSIG(status));
215696Spaul				rval |= 1;
216696Spaul			} else if (WIFEXITED(status) && WEXITSTATUS(status)) {
217696Spaul				fprintf(stderr, "%s: exit status %d\n",
218696Spaul						*argv, WEXITSTATUS(status));
219696Spaul				rval |= 1;
220696Spaul			}
221696Spaul			break;
222696Spaul		case 0:
223105439Ssobomax			if (is_shlib == 0) {
22490172Ssobomax				execl(*argv, *argv, (char *)NULL);
22590172Ssobomax				warn("%s", *argv);
226105439Ssobomax			} else {
227105439Ssobomax				dlopen(*argv, RTLD_TRACE);
228105439Ssobomax				warnx("%s: %s", *argv, dlerror());
22990172Ssobomax			}
230696Spaul			_exit(1);
231696Spaul		}
232696Spaul	}
233696Spaul
234696Spaul	return rval;
235696Spaul}
236