1330449Seadler/*-
2330449Seadler * SPDX-License-Identifier: BSD-4-Clause
3330449Seadler *
4696Spaul * Copyright (c) 1993 Paul Kranenburg
5696Spaul * All rights reserved.
6696Spaul *
7696Spaul * Redistribution and use in source and binary forms, with or without
8696Spaul * modification, are permitted provided that the following conditions
9696Spaul * are met:
10696Spaul * 1. Redistributions of source code must retain the above copyright
11696Spaul *    notice, this list of conditions and the following disclaimer.
12696Spaul * 2. Redistributions in binary form must reproduce the above copyright
13696Spaul *    notice, this list of conditions and the following disclaimer in the
14696Spaul *    documentation and/or other materials provided with the distribution.
15696Spaul * 3. All advertising materials mentioning features or use of this software
16696Spaul *    must display the following acknowledgement:
17696Spaul *      This product includes software developed by Paul Kranenburg.
18696Spaul * 4. The name of the author may not be used to endorse or promote products
191153Sjkh *    derived from this software without specific prior written permission
20696Spaul *
21696Spaul * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22696Spaul * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23696Spaul * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24696Spaul * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25696Spaul * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26696Spaul * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27696Spaul * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28696Spaul * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29696Spaul * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30696Spaul * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31696Spaul */
32696Spaul
3395648Smarkm#include <sys/cdefs.h>
3495648Smarkm__FBSDID("$FreeBSD: stable/11/usr.bin/ldd/ldd.c 362427 2020-06-20 04:41:04Z kib $");
3569827Scharnier
36696Spaul#include <sys/wait.h>
3795648Smarkm
3876224Sobrien#include <machine/elf.h>
3995648Smarkm
4095153Smike#include <arpa/inet.h>
4195648Smarkm
4290172Ssobomax#include <dlfcn.h>
431741Srich#include <err.h>
44180236Sedwin#include <errno.h>
451741Srich#include <fcntl.h>
461741Srich#include <stdio.h>
471741Srich#include <stdlib.h>
48181136Sjhb#include <string.h>
491741Srich#include <unistd.h>
50696Spaul
5195648Smarkm#include "extern.h"
5218600Speter
53294665Sbr/* We don't support a.out executables on arm64 and riscv */
54294665Sbr#if !defined(__aarch64__) && !defined(__riscv__)
55280220Sandrew#include <a.out.h>
56280220Sandrew#define	AOUT_SUPPORTED
57280220Sandrew#endif
58280220Sandrew
59180646Sedwin/*
60180877Sedwin * 32-bit ELF data structures can only be used if the system header[s] declare
61180877Sedwin * them.  There is no official macro for determining whether they are declared,
62180877Sedwin * so check for the existence of one of the 32-macros defined in elf(5).
63180646Sedwin */
64180877Sedwin#ifdef ELF32_R_TYPE
65180877Sedwin#define	ELF32_SUPPORTED
66180646Sedwin#endif
67180646Sedwin
68254018Smarkj#define	LDD_SETENV(name, value, overwrite) do {		\
69254018Smarkj	setenv("LD_" name, value, overwrite);		\
70254018Smarkj	setenv("LD_32_" name, value, overwrite);	\
71254018Smarkj} while (0)
72254018Smarkj
73254018Smarkj#define	LDD_UNSETENV(name) do {		\
74254018Smarkj	unsetenv("LD_" name);		\
75254018Smarkj	unsetenv("LD_32_" name);	\
76254018Smarkj} while (0)
77254018Smarkj
78180235Sedwinstatic int	is_executable(const char *fname, int fd, int *is_shlib,
79180235Sedwin		    int *type);
80180235Sedwinstatic void	usage(void);
81180234Sedwin
82180235Sedwin#define	TYPE_UNKNOWN	0
83180235Sedwin#define	TYPE_AOUT	1
84180235Sedwin#define	TYPE_ELF	2	/* Architecture default */
85180646Sedwin#if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED)
86180236Sedwin#define	TYPE_ELF32	3	/* Explicit 32 bits on architectures >32 bits */
87696Spaul
88181136Sjhb#define	_PATH_LDD32	"/usr/bin/ldd32"
89180235Sedwin
90181136Sjhbstatic int
91181136Sjhbexecldd32(char *file, char *fmt1, char *fmt2, int aflag, int vflag)
92181136Sjhb{
93299952Struckman	char *argv[9];
94181136Sjhb	int i, rval, status;
95181136Sjhb
96254018Smarkj	LDD_UNSETENV("TRACE_LOADED_OBJECTS");
97181136Sjhb	rval = 0;
98181136Sjhb	i = 0;
99181136Sjhb	argv[i++] = strdup(_PATH_LDD32);
100181136Sjhb	if (aflag)
101181136Sjhb		argv[i++] = strdup("-a");
102181136Sjhb	if (vflag)
103181136Sjhb		argv[i++] = strdup("-v");
104181161Sjhb	if (fmt1 != NULL) {
105181136Sjhb		argv[i++] = strdup("-f");
106181136Sjhb		argv[i++] = strdup(fmt1);
107181136Sjhb	}
108181161Sjhb	if (fmt2 != NULL) {
109181136Sjhb		argv[i++] = strdup("-f");
110181136Sjhb		argv[i++] = strdup(fmt2);
111181136Sjhb	}
112181136Sjhb	argv[i++] = strdup(file);
113181136Sjhb	argv[i++] = NULL;
114181136Sjhb
115181136Sjhb	switch (fork()) {
116181136Sjhb	case -1:
117181136Sjhb		err(1, "fork");
118181136Sjhb		break;
119181136Sjhb	case 0:
120181136Sjhb		execv(_PATH_LDD32, argv);
121181136Sjhb		warn("%s", _PATH_LDD32);
122181161Sjhb		_exit(127);
123181136Sjhb		break;
124181136Sjhb	default:
125181161Sjhb		if (wait(&status) < 0)
126181136Sjhb			rval = 1;
127181161Sjhb		else if (WIFSIGNALED(status))
128181136Sjhb			rval = 1;
129181161Sjhb		else if (WIFEXITED(status) && WEXITSTATUS(status) != 0)
130181136Sjhb			rval = 1;
131181136Sjhb		break;
132181136Sjhb	}
133181136Sjhb	while (i--)
134181136Sjhb		free(argv[i]);
135254018Smarkj	LDD_SETENV("TRACE_LOADED_OBJECTS", "yes", 1);
136181136Sjhb	return (rval);
137181136Sjhb}
138180236Sedwin#endif
139180235Sedwin
140696Spaulint
14195648Smarkmmain(int argc, char *argv[])
142696Spaul{
143180234Sedwin	char *fmt1, *fmt2;
144180234Sedwin	int rval, c, aflag, vflag;
145696Spaul
14690755Sobrien	aflag = vflag = 0;
147180234Sedwin	fmt1 = fmt2 = NULL;
14890755Sobrien
149180234Sedwin	while ((c = getopt(argc, argv, "af:v")) != -1) {
150696Spaul		switch (c) {
15190755Sobrien		case 'a':
15290755Sobrien			aflag++;
15390755Sobrien			break;
15418598Speter		case 'f':
155180234Sedwin			if (fmt1 != NULL) {
156180234Sedwin				if (fmt2 != NULL)
15769827Scharnier					errx(1, "too many formats");
15818598Speter				fmt2 = optarg;
15918598Speter			} else
16018598Speter				fmt1 = optarg;
16118598Speter			break;
162180234Sedwin		case 'v':
163180234Sedwin			vflag++;
164180234Sedwin			break;
165696Spaul		default:
166696Spaul			usage();
167180234Sedwin			/* NOTREACHED */
168696Spaul		}
169696Spaul	}
170696Spaul	argc -= optind;
171696Spaul	argv += optind;
172696Spaul
173180234Sedwin	if (vflag && fmt1 != NULL)
17418600Speter		errx(1, "-v may not be used with -f");
17518600Speter
176696Spaul	if (argc <= 0) {
177696Spaul		usage();
178180234Sedwin		/* NOTREACHED */
179696Spaul	}
180696Spaul
18139354Sdfr#ifdef __i386__
18218600Speter	if (vflag) {
18318600Speter		for (c = 0; c < argc; c++)
18418600Speter			dump_file(argv[c]);
18518600Speter		exit(error_count == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
18618600Speter	}
18739354Sdfr#endif
18818600Speter
1891741Srich	rval = 0;
190180234Sedwin	for (; argc > 0; argc--, argv++) {
191180235Sedwin		int fd, status, is_shlib, rv, type;
192696Spaul
193696Spaul		if ((fd = open(*argv, O_RDONLY, 0)) < 0) {
1941741Srich			warn("%s", *argv);
195696Spaul			rval |= 1;
196696Spaul			continue;
197696Spaul		}
198180235Sedwin		rv = is_executable(*argv, fd, &is_shlib, &type);
199180235Sedwin		close(fd);
200180235Sedwin		if (rv == 0) {
201696Spaul			rval |= 1;
202696Spaul			continue;
203696Spaul		}
20435575Sdfr
205180236Sedwin		switch (type) {
206180236Sedwin		case TYPE_ELF:
207180236Sedwin		case TYPE_AOUT:
208180236Sedwin			break;
209180646Sedwin#if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED)
210180236Sedwin		case TYPE_ELF32:
211181136Sjhb			rval |= execldd32(*argv, fmt1, fmt2, aflag, vflag);
212181136Sjhb			continue;
213180236Sedwin#endif
214180236Sedwin		case TYPE_UNKNOWN:
215180236Sedwin		default:
216180236Sedwin			/*
217180236Sedwin			 * This shouldn't happen unless is_executable()
218180236Sedwin			 * is broken.
219180236Sedwin			 */
220180236Sedwin			errx(EDOOFUS, "unknown executable type");
221180236Sedwin		}
222180236Sedwin
223180235Sedwin		/* ld.so magic */
224254018Smarkj		LDD_SETENV("TRACE_LOADED_OBJECTS", "yes", 1);
225180235Sedwin		if (fmt1 != NULL)
226254018Smarkj			LDD_SETENV("TRACE_LOADED_OBJECTS_FMT1", fmt1, 1);
227180235Sedwin		if (fmt2 != NULL)
228254018Smarkj			LDD_SETENV("TRACE_LOADED_OBJECTS_FMT2", fmt2, 1);
22935575Sdfr
230254018Smarkj		LDD_SETENV("TRACE_LOADED_OBJECTS_PROGNAME", *argv, 1);
231180234Sedwin		if (aflag)
232254018Smarkj			LDD_SETENV("TRACE_LOADED_OBJECTS_ALL", "1", 1);
23390755Sobrien		else if (fmt1 == NULL && fmt2 == NULL)
23418598Speter			/* Default formats */
23518598Speter			printf("%s:\n", *argv);
2361153Sjkh		fflush(stdout);
237696Spaul
238696Spaul		switch (fork()) {
239696Spaul		case -1:
2401741Srich			err(1, "fork");
241696Spaul			break;
242696Spaul		default:
243181161Sjhb			if (wait(&status) < 0) {
2441741Srich				warn("wait");
2451741Srich				rval |= 1;
2461741Srich			} else if (WIFSIGNALED(status)) {
247180234Sedwin				fprintf(stderr, "%s: signal %d\n", *argv,
248180234Sedwin				    WTERMSIG(status));
249696Spaul				rval |= 1;
250181161Sjhb			} else if (WIFEXITED(status) &&
251181161Sjhb			    WEXITSTATUS(status) != 0) {
252180234Sedwin				fprintf(stderr, "%s: exit status %d\n", *argv,
253180234Sedwin				    WEXITSTATUS(status));
254696Spaul				rval |= 1;
255696Spaul			}
256696Spaul			break;
257696Spaul		case 0:
258105439Ssobomax			if (is_shlib == 0) {
25990172Ssobomax				execl(*argv, *argv, (char *)NULL);
26090172Ssobomax				warn("%s", *argv);
261105439Ssobomax			} else {
262105439Ssobomax				dlopen(*argv, RTLD_TRACE);
263105439Ssobomax				warnx("%s: %s", *argv, dlerror());
26490172Ssobomax			}
265696Spaul			_exit(1);
266696Spaul		}
267696Spaul	}
268696Spaul
269696Spaul	return rval;
270696Spaul}
271180235Sedwin
272180235Sedwinstatic void
273180235Sedwinusage(void)
274180235Sedwin{
275180235Sedwin
276180235Sedwin	fprintf(stderr, "usage: ldd [-a] [-v] [-f format] program ...\n");
277180235Sedwin	exit(1);
278180235Sedwin}
279180235Sedwin
280180235Sedwinstatic int
281180235Sedwinis_executable(const char *fname, int fd, int *is_shlib, int *type)
282180235Sedwin{
283180235Sedwin	union {
284280220Sandrew#ifdef AOUT_SUPPORTED
285180235Sedwin		struct exec aout;
286280220Sandrew#endif
287180646Sedwin#if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED)
288180236Sedwin		Elf32_Ehdr elf32;
289180646Sedwin#endif
290180235Sedwin		Elf_Ehdr elf;
291180235Sedwin	} hdr;
292362427Skib	Elf_Phdr phdr, dynphdr;
293362427Skib	Elf_Dyn *dynp;
294362427Skib	void *dyndata;
295362427Skib#if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED)
296362427Skib	Elf32_Phdr phdr32, dynphdr32;
297362427Skib	Elf32_Dyn *dynp32;
298362427Skib#endif
299362427Skib	int df1pie, dynamic, i, n;
300180235Sedwin
301180235Sedwin	*is_shlib = 0;
302180235Sedwin	*type = TYPE_UNKNOWN;
303362427Skib	df1pie = 0;
304180235Sedwin
305180235Sedwin	if ((n = read(fd, &hdr, sizeof(hdr))) == -1) {
306180235Sedwin		warn("%s: can't read program header", fname);
307180235Sedwin		return (0);
308180235Sedwin	}
309180235Sedwin
310280220Sandrew#ifdef AOUT_SUPPORTED
311180235Sedwin	if ((size_t)n >= sizeof(hdr.aout) && !N_BADMAG(hdr.aout)) {
312180235Sedwin		/* a.out file */
313180235Sedwin		if ((N_GETFLAG(hdr.aout) & EX_DPMASK) != EX_DYNAMIC
314180235Sedwin#if 1 /* Compatibility */
315180235Sedwin		    || hdr.aout.a_entry < __LDPGSZ
316180235Sedwin#endif
317180235Sedwin			) {
318180235Sedwin			warnx("%s: not a dynamic executable", fname);
319180235Sedwin			return (0);
320180235Sedwin		}
321180235Sedwin		*type = TYPE_AOUT;
322180235Sedwin		return (1);
323180235Sedwin	}
324280220Sandrew#endif
325180235Sedwin
326180646Sedwin#if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED)
327180236Sedwin	if ((size_t)n >= sizeof(hdr.elf32) && IS_ELF(hdr.elf32) &&
328180236Sedwin	    hdr.elf32.e_ident[EI_CLASS] == ELFCLASS32) {
329180236Sedwin		/* Handle 32 bit ELF objects */
330180236Sedwin
331180236Sedwin		dynamic = 0;
332180236Sedwin		*type = TYPE_ELF32;
333180236Sedwin
334180236Sedwin		if (lseek(fd, hdr.elf32.e_phoff, SEEK_SET) == -1) {
335180236Sedwin			warnx("%s: header too short", fname);
336180236Sedwin			return (0);
337180236Sedwin		}
338180236Sedwin		for (i = 0; i < hdr.elf32.e_phnum; i++) {
339362427Skib			if (read(fd, &phdr32, hdr.elf32.e_phentsize) !=
340362427Skib			    sizeof(phdr32)) {
341180236Sedwin				warnx("%s: can't read program header", fname);
342180236Sedwin				return (0);
343180236Sedwin			}
344362427Skib			if (phdr32.p_type == PT_DYNAMIC) {
345180236Sedwin				dynamic = 1;
346362427Skib				dynphdr32 = phdr32;
347180236Sedwin				break;
348180236Sedwin			}
349180236Sedwin		}
350180236Sedwin
351180236Sedwin		if (!dynamic) {
352180236Sedwin			warnx("%s: not a dynamic ELF executable", fname);
353180236Sedwin			return (0);
354180236Sedwin		}
355362427Skib
356180236Sedwin		if (hdr.elf32.e_type == ET_DYN) {
357362427Skib			if (lseek(fd, dynphdr32.p_offset, SEEK_SET) == -1) {
358362427Skib				warnx("%s: dynamic segment out of range",
359362427Skib				    fname);
360362427Skib				return (0);
361362427Skib			}
362362427Skib			dyndata = malloc(dynphdr32.p_filesz);
363362427Skib			if (dyndata == NULL) {
364362427Skib				warn("malloc");
365362427Skib				return (0);
366362427Skib			}
367362427Skib			if (read(fd, dyndata, dynphdr32.p_filesz) !=
368362427Skib			    (ssize_t)dynphdr32.p_filesz) {
369362427Skib				free(dyndata);
370362427Skib				warnx("%s: can't read dynamic segment", fname);
371362427Skib				return (0);
372362427Skib			}
373362427Skib			for (dynp32 = dyndata; dynp32->d_tag != DT_NULL;
374362427Skib			    dynp32++) {
375362427Skib				if (dynp32->d_tag != DT_FLAGS_1)
376362427Skib					continue;
377362427Skib				df1pie = (dynp32->d_un.d_val & DF_1_PIE) != 0;
378362427Skib				break;
379362427Skib			}
380362427Skib			free(dyndata);
381362427Skib
382215705Sbrucec			if (hdr.elf32.e_ident[EI_OSABI] == ELFOSABI_FREEBSD) {
383362427Skib				if (!df1pie)
384362427Skib					*is_shlib = 1;
385180236Sedwin				return (1);
386180236Sedwin			}
387180236Sedwin			warnx("%s: not a FreeBSD ELF shared object", fname);
388180236Sedwin			return (0);
389180236Sedwin		}
390180236Sedwin
391180236Sedwin		return (1);
392180236Sedwin	}
393180236Sedwin#endif
394180236Sedwin
395180235Sedwin	if ((size_t)n >= sizeof(hdr.elf) && IS_ELF(hdr.elf) &&
396180235Sedwin	    hdr.elf.e_ident[EI_CLASS] == ELF_TARG_CLASS) {
397180235Sedwin		/* Handle default ELF objects on this architecture */
398180235Sedwin
399180235Sedwin		dynamic = 0;
400180235Sedwin		*type = TYPE_ELF;
401180235Sedwin
402180235Sedwin		if (lseek(fd, hdr.elf.e_phoff, SEEK_SET) == -1) {
403180235Sedwin			warnx("%s: header too short", fname);
404180235Sedwin			return (0);
405180235Sedwin		}
406180235Sedwin		for (i = 0; i < hdr.elf.e_phnum; i++) {
407180235Sedwin			if (read(fd, &phdr, hdr.elf.e_phentsize)
408180235Sedwin			   != sizeof(phdr)) {
409180235Sedwin				warnx("%s: can't read program header", fname);
410180235Sedwin				return (0);
411180235Sedwin			}
412180235Sedwin			if (phdr.p_type == PT_DYNAMIC) {
413180235Sedwin				dynamic = 1;
414362427Skib				dynphdr = phdr;
415180235Sedwin				break;
416180235Sedwin			}
417180235Sedwin		}
418180235Sedwin
419180235Sedwin		if (!dynamic) {
420180235Sedwin			warnx("%s: not a dynamic ELF executable", fname);
421180235Sedwin			return (0);
422180235Sedwin		}
423362427Skib
424180235Sedwin		if (hdr.elf.e_type == ET_DYN) {
425362427Skib			if (lseek(fd, dynphdr.p_offset, SEEK_SET) == -1) {
426362427Skib				warnx("%s: dynamic segment out of range",
427362427Skib				    fname);
428362427Skib				return (0);
429362427Skib			}
430362427Skib			dyndata = malloc(dynphdr.p_filesz);
431362427Skib			if (dyndata == NULL) {
432362427Skib				warn("malloc");
433362427Skib				return (0);
434362427Skib			}
435362427Skib			if (read(fd, dyndata, dynphdr.p_filesz) !=
436362427Skib			    (ssize_t)dynphdr.p_filesz) {
437362427Skib				free(dyndata);
438362427Skib				warnx("%s: can't read dynamic segment", fname);
439362427Skib				return (0);
440362427Skib			}
441362427Skib			for (dynp = dyndata; dynp->d_tag != DT_NULL; dynp++) {
442362427Skib				if (dynp->d_tag != DT_FLAGS_1)
443362427Skib					continue;
444362427Skib				df1pie = (dynp->d_un.d_val & DF_1_PIE) != 0;
445362427Skib				break;
446362427Skib			}
447362427Skib			free(dyndata);
448362427Skib
449289425Sjkim			switch (hdr.elf.e_ident[EI_OSABI]) {
450289425Sjkim			case ELFOSABI_FREEBSD:
451362427Skib				if (!df1pie)
452362427Skib					*is_shlib = 1;
453180235Sedwin				return (1);
454289425Sjkim#ifdef __ARM_EABI__
455289425Sjkim			case ELFOSABI_NONE:
456289425Sjkim				if (hdr.elf.e_machine != EM_ARM)
457289425Sjkim					break;
458289425Sjkim				if (EF_ARM_EABI_VERSION(hdr.elf.e_flags) <
459289425Sjkim				    EF_ARM_EABI_FREEBSD_MIN)
460289425Sjkim					break;
461289425Sjkim				*is_shlib = 1;
462289425Sjkim				return (1);
463289425Sjkim#endif
464180235Sedwin			}
465180235Sedwin			warnx("%s: not a FreeBSD ELF shared object", fname);
466180235Sedwin			return (0);
467180235Sedwin		}
468180235Sedwin
469180235Sedwin		return (1);
470180235Sedwin	}
471180235Sedwin
472180235Sedwin	warnx("%s: not a dynamic executable", fname);
473180235Sedwin	return (0);
474180235Sedwin}
475