ldd.c revision 280220
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 280220 2015-03-18 13:59:04Z andrew $");
3369827Scharnier
34696Spaul#include <sys/wait.h>
3595648Smarkm
3676224Sobrien#include <machine/elf.h>
3795648Smarkm
3895153Smike#include <arpa/inet.h>
3995648Smarkm
4090172Ssobomax#include <dlfcn.h>
411741Srich#include <err.h>
42180236Sedwin#include <errno.h>
431741Srich#include <fcntl.h>
441741Srich#include <stdio.h>
451741Srich#include <stdlib.h>
46181136Sjhb#include <string.h>
471741Srich#include <unistd.h>
48696Spaul
4995648Smarkm#include "extern.h"
5018600Speter
51280220Sandrew/* We don't support a.out executables on arm64 */
52280220Sandrew#ifndef __aarch64__
53280220Sandrew#include <a.out.h>
54280220Sandrew#define	AOUT_SUPPORTED
55280220Sandrew#endif
56280220Sandrew
57180646Sedwin/*
58180877Sedwin * 32-bit ELF data structures can only be used if the system header[s] declare
59180877Sedwin * them.  There is no official macro for determining whether they are declared,
60180877Sedwin * so check for the existence of one of the 32-macros defined in elf(5).
61180646Sedwin */
62180877Sedwin#ifdef ELF32_R_TYPE
63180877Sedwin#define	ELF32_SUPPORTED
64180646Sedwin#endif
65180646Sedwin
66254018Smarkj#define	LDD_SETENV(name, value, overwrite) do {		\
67254018Smarkj	setenv("LD_" name, value, overwrite);		\
68254018Smarkj	setenv("LD_32_" name, value, overwrite);	\
69254018Smarkj} while (0)
70254018Smarkj
71254018Smarkj#define	LDD_UNSETENV(name) do {		\
72254018Smarkj	unsetenv("LD_" name);		\
73254018Smarkj	unsetenv("LD_32_" name);	\
74254018Smarkj} while (0)
75254018Smarkj
76180235Sedwinstatic int	is_executable(const char *fname, int fd, int *is_shlib,
77180235Sedwin		    int *type);
78180235Sedwinstatic void	usage(void);
79180234Sedwin
80180235Sedwin#define	TYPE_UNKNOWN	0
81180235Sedwin#define	TYPE_AOUT	1
82180235Sedwin#define	TYPE_ELF	2	/* Architecture default */
83180646Sedwin#if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED)
84180236Sedwin#define	TYPE_ELF32	3	/* Explicit 32 bits on architectures >32 bits */
85696Spaul
86181136Sjhb#define	_PATH_LDD32	"/usr/bin/ldd32"
87180235Sedwin
88181136Sjhbstatic int
89181136Sjhbexecldd32(char *file, char *fmt1, char *fmt2, int aflag, int vflag)
90181136Sjhb{
91181136Sjhb	char *argv[8];
92181136Sjhb	int i, rval, status;
93181136Sjhb
94254018Smarkj	LDD_UNSETENV("TRACE_LOADED_OBJECTS");
95181136Sjhb	rval = 0;
96181136Sjhb	i = 0;
97181136Sjhb	argv[i++] = strdup(_PATH_LDD32);
98181136Sjhb	if (aflag)
99181136Sjhb		argv[i++] = strdup("-a");
100181136Sjhb	if (vflag)
101181136Sjhb		argv[i++] = strdup("-v");
102181161Sjhb	if (fmt1 != NULL) {
103181136Sjhb		argv[i++] = strdup("-f");
104181136Sjhb		argv[i++] = strdup(fmt1);
105181136Sjhb	}
106181161Sjhb	if (fmt2 != NULL) {
107181136Sjhb		argv[i++] = strdup("-f");
108181136Sjhb		argv[i++] = strdup(fmt2);
109181136Sjhb	}
110181136Sjhb	argv[i++] = strdup(file);
111181136Sjhb	argv[i++] = NULL;
112181136Sjhb
113181136Sjhb	switch (fork()) {
114181136Sjhb	case -1:
115181136Sjhb		err(1, "fork");
116181136Sjhb		break;
117181136Sjhb	case 0:
118181136Sjhb		execv(_PATH_LDD32, argv);
119181136Sjhb		warn("%s", _PATH_LDD32);
120181161Sjhb		_exit(127);
121181136Sjhb		break;
122181136Sjhb	default:
123181161Sjhb		if (wait(&status) < 0)
124181136Sjhb			rval = 1;
125181161Sjhb		else if (WIFSIGNALED(status))
126181136Sjhb			rval = 1;
127181161Sjhb		else if (WIFEXITED(status) && WEXITSTATUS(status) != 0)
128181136Sjhb			rval = 1;
129181136Sjhb		break;
130181136Sjhb	}
131181136Sjhb	while (i--)
132181136Sjhb		free(argv[i]);
133254018Smarkj	LDD_SETENV("TRACE_LOADED_OBJECTS", "yes", 1);
134181136Sjhb	return (rval);
135181136Sjhb}
136180236Sedwin#endif
137180235Sedwin
138696Spaulint
13995648Smarkmmain(int argc, char *argv[])
140696Spaul{
141180234Sedwin	char *fmt1, *fmt2;
142180234Sedwin	int rval, c, aflag, vflag;
143696Spaul
14490755Sobrien	aflag = vflag = 0;
145180234Sedwin	fmt1 = fmt2 = NULL;
14690755Sobrien
147180234Sedwin	while ((c = getopt(argc, argv, "af:v")) != -1) {
148696Spaul		switch (c) {
14990755Sobrien		case 'a':
15090755Sobrien			aflag++;
15190755Sobrien			break;
15218598Speter		case 'f':
153180234Sedwin			if (fmt1 != NULL) {
154180234Sedwin				if (fmt2 != NULL)
15569827Scharnier					errx(1, "too many formats");
15618598Speter				fmt2 = optarg;
15718598Speter			} else
15818598Speter				fmt1 = optarg;
15918598Speter			break;
160180234Sedwin		case 'v':
161180234Sedwin			vflag++;
162180234Sedwin			break;
163696Spaul		default:
164696Spaul			usage();
165180234Sedwin			/* NOTREACHED */
166696Spaul		}
167696Spaul	}
168696Spaul	argc -= optind;
169696Spaul	argv += optind;
170696Spaul
171180234Sedwin	if (vflag && fmt1 != NULL)
17218600Speter		errx(1, "-v may not be used with -f");
17318600Speter
174696Spaul	if (argc <= 0) {
175696Spaul		usage();
176180234Sedwin		/* NOTREACHED */
177696Spaul	}
178696Spaul
17939354Sdfr#ifdef __i386__
18018600Speter	if (vflag) {
18118600Speter		for (c = 0; c < argc; c++)
18218600Speter			dump_file(argv[c]);
18318600Speter		exit(error_count == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
18418600Speter	}
18539354Sdfr#endif
18618600Speter
1871741Srich	rval = 0;
188180234Sedwin	for (; argc > 0; argc--, argv++) {
189180235Sedwin		int fd, status, is_shlib, rv, type;
190696Spaul
191696Spaul		if ((fd = open(*argv, O_RDONLY, 0)) < 0) {
1921741Srich			warn("%s", *argv);
193696Spaul			rval |= 1;
194696Spaul			continue;
195696Spaul		}
196180235Sedwin		rv = is_executable(*argv, fd, &is_shlib, &type);
197180235Sedwin		close(fd);
198180235Sedwin		if (rv == 0) {
199696Spaul			rval |= 1;
200696Spaul			continue;
201696Spaul		}
20235575Sdfr
203180236Sedwin		switch (type) {
204180236Sedwin		case TYPE_ELF:
205180236Sedwin		case TYPE_AOUT:
206180236Sedwin			break;
207180646Sedwin#if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED)
208180236Sedwin		case TYPE_ELF32:
209181136Sjhb			rval |= execldd32(*argv, fmt1, fmt2, aflag, vflag);
210181136Sjhb			continue;
211180236Sedwin#endif
212180236Sedwin		case TYPE_UNKNOWN:
213180236Sedwin		default:
214180236Sedwin			/*
215180236Sedwin			 * This shouldn't happen unless is_executable()
216180236Sedwin			 * is broken.
217180236Sedwin			 */
218180236Sedwin			errx(EDOOFUS, "unknown executable type");
219180236Sedwin		}
220180236Sedwin
221180235Sedwin		/* ld.so magic */
222254018Smarkj		LDD_SETENV("TRACE_LOADED_OBJECTS", "yes", 1);
223180235Sedwin		if (fmt1 != NULL)
224254018Smarkj			LDD_SETENV("TRACE_LOADED_OBJECTS_FMT1", fmt1, 1);
225180235Sedwin		if (fmt2 != NULL)
226254018Smarkj			LDD_SETENV("TRACE_LOADED_OBJECTS_FMT2", fmt2, 1);
22735575Sdfr
228254018Smarkj		LDD_SETENV("TRACE_LOADED_OBJECTS_PROGNAME", *argv, 1);
229180234Sedwin		if (aflag)
230254018Smarkj			LDD_SETENV("TRACE_LOADED_OBJECTS_ALL", "1", 1);
23190755Sobrien		else if (fmt1 == NULL && fmt2 == NULL)
23218598Speter			/* Default formats */
23318598Speter			printf("%s:\n", *argv);
2341153Sjkh		fflush(stdout);
235696Spaul
236696Spaul		switch (fork()) {
237696Spaul		case -1:
2381741Srich			err(1, "fork");
239696Spaul			break;
240696Spaul		default:
241181161Sjhb			if (wait(&status) < 0) {
2421741Srich				warn("wait");
2431741Srich				rval |= 1;
2441741Srich			} else if (WIFSIGNALED(status)) {
245180234Sedwin				fprintf(stderr, "%s: signal %d\n", *argv,
246180234Sedwin				    WTERMSIG(status));
247696Spaul				rval |= 1;
248181161Sjhb			} else if (WIFEXITED(status) &&
249181161Sjhb			    WEXITSTATUS(status) != 0) {
250180234Sedwin				fprintf(stderr, "%s: exit status %d\n", *argv,
251180234Sedwin				    WEXITSTATUS(status));
252696Spaul				rval |= 1;
253696Spaul			}
254696Spaul			break;
255696Spaul		case 0:
256105439Ssobomax			if (is_shlib == 0) {
25790172Ssobomax				execl(*argv, *argv, (char *)NULL);
25890172Ssobomax				warn("%s", *argv);
259105439Ssobomax			} else {
260105439Ssobomax				dlopen(*argv, RTLD_TRACE);
261105439Ssobomax				warnx("%s: %s", *argv, dlerror());
26290172Ssobomax			}
263696Spaul			_exit(1);
264696Spaul		}
265696Spaul	}
266696Spaul
267696Spaul	return rval;
268696Spaul}
269180235Sedwin
270180235Sedwinstatic void
271180235Sedwinusage(void)
272180235Sedwin{
273180235Sedwin
274180235Sedwin	fprintf(stderr, "usage: ldd [-a] [-v] [-f format] program ...\n");
275180235Sedwin	exit(1);
276180235Sedwin}
277180235Sedwin
278180235Sedwinstatic int
279180235Sedwinis_executable(const char *fname, int fd, int *is_shlib, int *type)
280180235Sedwin{
281180235Sedwin	union {
282280220Sandrew#ifdef AOUT_SUPPORTED
283180235Sedwin		struct exec aout;
284280220Sandrew#endif
285180646Sedwin#if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED)
286180236Sedwin		Elf32_Ehdr elf32;
287180646Sedwin#endif
288180235Sedwin		Elf_Ehdr elf;
289180235Sedwin	} hdr;
290180235Sedwin	int n;
291180235Sedwin
292180235Sedwin	*is_shlib = 0;
293180235Sedwin	*type = TYPE_UNKNOWN;
294180235Sedwin
295180235Sedwin	if ((n = read(fd, &hdr, sizeof(hdr))) == -1) {
296180235Sedwin		warn("%s: can't read program header", fname);
297180235Sedwin		return (0);
298180235Sedwin	}
299180235Sedwin
300280220Sandrew#ifdef AOUT_SUPPORTED
301180235Sedwin	if ((size_t)n >= sizeof(hdr.aout) && !N_BADMAG(hdr.aout)) {
302180235Sedwin		/* a.out file */
303180235Sedwin		if ((N_GETFLAG(hdr.aout) & EX_DPMASK) != EX_DYNAMIC
304180235Sedwin#if 1 /* Compatibility */
305180235Sedwin		    || hdr.aout.a_entry < __LDPGSZ
306180235Sedwin#endif
307180235Sedwin			) {
308180235Sedwin			warnx("%s: not a dynamic executable", fname);
309180235Sedwin			return (0);
310180235Sedwin		}
311180235Sedwin		*type = TYPE_AOUT;
312180235Sedwin		return (1);
313180235Sedwin	}
314280220Sandrew#endif
315180235Sedwin
316180646Sedwin#if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED)
317180236Sedwin	if ((size_t)n >= sizeof(hdr.elf32) && IS_ELF(hdr.elf32) &&
318180236Sedwin	    hdr.elf32.e_ident[EI_CLASS] == ELFCLASS32) {
319180236Sedwin		/* Handle 32 bit ELF objects */
320180236Sedwin		Elf32_Phdr phdr;
321180236Sedwin		int dynamic, i;
322180236Sedwin
323180236Sedwin		dynamic = 0;
324180236Sedwin		*type = TYPE_ELF32;
325180236Sedwin
326180236Sedwin		if (lseek(fd, hdr.elf32.e_phoff, SEEK_SET) == -1) {
327180236Sedwin			warnx("%s: header too short", fname);
328180236Sedwin			return (0);
329180236Sedwin		}
330180236Sedwin		for (i = 0; i < hdr.elf32.e_phnum; i++) {
331180236Sedwin			if (read(fd, &phdr, hdr.elf32.e_phentsize) !=
332180236Sedwin			    sizeof(phdr)) {
333180236Sedwin				warnx("%s: can't read program header", fname);
334180236Sedwin				return (0);
335180236Sedwin			}
336180236Sedwin			if (phdr.p_type == PT_DYNAMIC) {
337180236Sedwin				dynamic = 1;
338180236Sedwin				break;
339180236Sedwin			}
340180236Sedwin		}
341180236Sedwin
342180236Sedwin		if (!dynamic) {
343180236Sedwin			warnx("%s: not a dynamic ELF executable", fname);
344180236Sedwin			return (0);
345180236Sedwin		}
346180236Sedwin		if (hdr.elf32.e_type == ET_DYN) {
347215705Sbrucec			if (hdr.elf32.e_ident[EI_OSABI] == ELFOSABI_FREEBSD) {
348180236Sedwin				*is_shlib = 1;
349180236Sedwin				return (1);
350180236Sedwin			}
351180236Sedwin			warnx("%s: not a FreeBSD ELF shared object", fname);
352180236Sedwin			return (0);
353180236Sedwin		}
354180236Sedwin
355180236Sedwin		return (1);
356180236Sedwin	}
357180236Sedwin#endif
358180236Sedwin
359180235Sedwin	if ((size_t)n >= sizeof(hdr.elf) && IS_ELF(hdr.elf) &&
360180235Sedwin	    hdr.elf.e_ident[EI_CLASS] == ELF_TARG_CLASS) {
361180235Sedwin		/* Handle default ELF objects on this architecture */
362180235Sedwin		Elf_Phdr phdr;
363180235Sedwin		int dynamic, i;
364180235Sedwin
365180235Sedwin		dynamic = 0;
366180235Sedwin		*type = TYPE_ELF;
367180235Sedwin
368180235Sedwin		if (lseek(fd, hdr.elf.e_phoff, SEEK_SET) == -1) {
369180235Sedwin			warnx("%s: header too short", fname);
370180235Sedwin			return (0);
371180235Sedwin		}
372180235Sedwin		for (i = 0; i < hdr.elf.e_phnum; i++) {
373180235Sedwin			if (read(fd, &phdr, hdr.elf.e_phentsize)
374180235Sedwin			   != sizeof(phdr)) {
375180235Sedwin				warnx("%s: can't read program header", fname);
376180235Sedwin				return (0);
377180235Sedwin			}
378180235Sedwin			if (phdr.p_type == PT_DYNAMIC) {
379180235Sedwin				dynamic = 1;
380180235Sedwin				break;
381180235Sedwin			}
382180235Sedwin		}
383180235Sedwin
384180235Sedwin		if (!dynamic) {
385180235Sedwin			warnx("%s: not a dynamic ELF executable", fname);
386180235Sedwin			return (0);
387180235Sedwin		}
388180235Sedwin		if (hdr.elf.e_type == ET_DYN) {
389215705Sbrucec			if (hdr.elf.e_ident[EI_OSABI] == ELFOSABI_FREEBSD) {
390180235Sedwin				*is_shlib = 1;
391180235Sedwin				return (1);
392180235Sedwin			}
393180235Sedwin			warnx("%s: not a FreeBSD ELF shared object", fname);
394180235Sedwin			return (0);
395180235Sedwin		}
396180235Sedwin
397180235Sedwin		return (1);
398180235Sedwin	}
399180235Sedwin
400180235Sedwin	warnx("%s: not a dynamic executable", fname);
401180235Sedwin	return (0);
402180235Sedwin}
403