xref: /freebsd/usr.bin/ldd/ldd.c (revision 2b5d88fdcfc22b0a2336ab0c5276a1d2c3d25f54)
11de7b4b8SPedro F. Giffuni /*-
21de7b4b8SPedro F. Giffuni  * SPDX-License-Identifier: BSD-4-Clause
31de7b4b8SPedro F. Giffuni  *
4b9ae52e3SPaul Richards  * Copyright (c) 1993 Paul Kranenburg
5b9ae52e3SPaul Richards  * All rights reserved.
6b9ae52e3SPaul Richards  *
7b9ae52e3SPaul Richards  * Redistribution and use in source and binary forms, with or without
8b9ae52e3SPaul Richards  * modification, are permitted provided that the following conditions
9b9ae52e3SPaul Richards  * are met:
10b9ae52e3SPaul Richards  * 1. Redistributions of source code must retain the above copyright
11b9ae52e3SPaul Richards  *    notice, this list of conditions and the following disclaimer.
12b9ae52e3SPaul Richards  * 2. Redistributions in binary form must reproduce the above copyright
13b9ae52e3SPaul Richards  *    notice, this list of conditions and the following disclaimer in the
14b9ae52e3SPaul Richards  *    documentation and/or other materials provided with the distribution.
15b9ae52e3SPaul Richards  * 3. All advertising materials mentioning features or use of this software
16b9ae52e3SPaul Richards  *    must display the following acknowledgement:
17b9ae52e3SPaul Richards  *      This product includes software developed by Paul Kranenburg.
18b9ae52e3SPaul Richards  * 4. The name of the author may not be used to endorse or promote products
1909e3d49dSJordan K. Hubbard  *    derived from this software without specific prior written permission
20b9ae52e3SPaul Richards  *
21b9ae52e3SPaul Richards  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22b9ae52e3SPaul Richards  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23b9ae52e3SPaul Richards  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24b9ae52e3SPaul Richards  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25b9ae52e3SPaul Richards  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26b9ae52e3SPaul Richards  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27b9ae52e3SPaul Richards  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28b9ae52e3SPaul Richards  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29b9ae52e3SPaul Richards  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30b9ae52e3SPaul Richards  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31b9ae52e3SPaul Richards  */
32b9ae52e3SPaul Richards 
33a53809fdSMark Murray #include <sys/cdefs.h>
34a53809fdSMark Murray __FBSDID("$FreeBSD$");
353e762626SPhilippe Charnier 
36b9ae52e3SPaul Richards #include <sys/wait.h>
37a53809fdSMark Murray 
385e6220d9SDavid E. O'Brien #include <machine/elf.h>
39a53809fdSMark Murray 
40a2cfdda8SMike Barcroft #include <arpa/inet.h>
41a53809fdSMark Murray 
42c6de4ce7SMaxim Sobolev #include <dlfcn.h>
43699e1b82SRich Murphey #include <err.h>
44fffd993dSEdwin Groothuis #include <errno.h>
45699e1b82SRich Murphey #include <fcntl.h>
46699e1b82SRich Murphey #include <stdio.h>
47699e1b82SRich Murphey #include <stdlib.h>
48e68ed793SJohn Baldwin #include <string.h>
49699e1b82SRich Murphey #include <unistd.h>
50b9ae52e3SPaul Richards 
51a53809fdSMark Murray #include "extern.h"
529731d137SPeter Wemm 
535a0bf0f5SRuslan Bukin /* We don't support a.out executables on arm64 and riscv */
54ca20f8ecSRuslan Bukin #if !defined(__aarch64__) && !defined(__riscv)
55e1f65999SAndrew Turner #include <a.out.h>
56e1f65999SAndrew Turner #define	AOUT_SUPPORTED
57e1f65999SAndrew Turner #endif
58e1f65999SAndrew Turner 
598bd833ffSEdwin Groothuis /*
60bff71350SEdwin Groothuis  * 32-bit ELF data structures can only be used if the system header[s] declare
61bff71350SEdwin Groothuis  * them.  There is no official macro for determining whether they are declared,
62bff71350SEdwin Groothuis  * so check for the existence of one of the 32-macros defined in elf(5).
638bd833ffSEdwin Groothuis  */
64bff71350SEdwin Groothuis #ifdef ELF32_R_TYPE
658bd833ffSEdwin Groothuis #define	ELF32_SUPPORTED
668bd833ffSEdwin Groothuis #endif
678bd833ffSEdwin Groothuis 
68a94a4b74SMark Johnston #define	LDD_SETENV(name, value, overwrite) do {		\
69a94a4b74SMark Johnston 	setenv("LD_" name, value, overwrite);		\
70a94a4b74SMark Johnston 	setenv("LD_32_" name, value, overwrite);	\
71a94a4b74SMark Johnston } while (0)
72a94a4b74SMark Johnston 
73a94a4b74SMark Johnston #define	LDD_UNSETENV(name) do {		\
74a94a4b74SMark Johnston 	unsetenv("LD_" name);		\
75a94a4b74SMark Johnston 	unsetenv("LD_32_" name);	\
76a94a4b74SMark Johnston } while (0)
77a94a4b74SMark Johnston 
78d3c1e14bSEdwin Groothuis static int	is_executable(const char *fname, int fd, int *is_shlib,
79d3c1e14bSEdwin Groothuis 		    int *type);
80d3c1e14bSEdwin Groothuis static void	usage(void);
81a0d476a9SEdwin Groothuis 
82d3c1e14bSEdwin Groothuis #define	TYPE_UNKNOWN	0
83d3c1e14bSEdwin Groothuis #define	TYPE_AOUT	1
84d3c1e14bSEdwin Groothuis #define	TYPE_ELF	2	/* Architecture default */
858bd833ffSEdwin Groothuis #if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED)
86fffd993dSEdwin Groothuis #define	TYPE_ELF32	3	/* Explicit 32 bits on architectures >32 bits */
87d3c1e14bSEdwin Groothuis 
88e68ed793SJohn Baldwin #define	_PATH_LDD32	"/usr/bin/ldd32"
89d3c1e14bSEdwin Groothuis 
90e68ed793SJohn Baldwin static int
91e68ed793SJohn Baldwin execldd32(char *file, char *fmt1, char *fmt2, int aflag, int vflag)
92e68ed793SJohn Baldwin {
934b426307SDon Lewis 	char *argv[9];
94e68ed793SJohn Baldwin 	int i, rval, status;
95e68ed793SJohn Baldwin 
96a94a4b74SMark Johnston 	LDD_UNSETENV("TRACE_LOADED_OBJECTS");
97e68ed793SJohn Baldwin 	rval = 0;
98e68ed793SJohn Baldwin 	i = 0;
99e68ed793SJohn Baldwin 	argv[i++] = strdup(_PATH_LDD32);
100e68ed793SJohn Baldwin 	if (aflag)
101e68ed793SJohn Baldwin 		argv[i++] = strdup("-a");
102e68ed793SJohn Baldwin 	if (vflag)
103e68ed793SJohn Baldwin 		argv[i++] = strdup("-v");
10452122f31SJohn Baldwin 	if (fmt1 != NULL) {
105e68ed793SJohn Baldwin 		argv[i++] = strdup("-f");
106e68ed793SJohn Baldwin 		argv[i++] = strdup(fmt1);
107e68ed793SJohn Baldwin 	}
10852122f31SJohn Baldwin 	if (fmt2 != NULL) {
109e68ed793SJohn Baldwin 		argv[i++] = strdup("-f");
110e68ed793SJohn Baldwin 		argv[i++] = strdup(fmt2);
111e68ed793SJohn Baldwin 	}
112e68ed793SJohn Baldwin 	argv[i++] = strdup(file);
113e68ed793SJohn Baldwin 	argv[i++] = NULL;
114e68ed793SJohn Baldwin 
115e68ed793SJohn Baldwin 	switch (fork()) {
116e68ed793SJohn Baldwin 	case -1:
117e68ed793SJohn Baldwin 		err(1, "fork");
118e68ed793SJohn Baldwin 		break;
119e68ed793SJohn Baldwin 	case 0:
120e68ed793SJohn Baldwin 		execv(_PATH_LDD32, argv);
121e68ed793SJohn Baldwin 		warn("%s", _PATH_LDD32);
12252122f31SJohn Baldwin 		_exit(127);
123e68ed793SJohn Baldwin 		break;
124e68ed793SJohn Baldwin 	default:
12552122f31SJohn Baldwin 		if (wait(&status) < 0)
126e68ed793SJohn Baldwin 			rval = 1;
12752122f31SJohn Baldwin 		else if (WIFSIGNALED(status))
128e68ed793SJohn Baldwin 			rval = 1;
12952122f31SJohn Baldwin 		else if (WIFEXITED(status) && WEXITSTATUS(status) != 0)
130e68ed793SJohn Baldwin 			rval = 1;
131e68ed793SJohn Baldwin 		break;
132e68ed793SJohn Baldwin 	}
133e68ed793SJohn Baldwin 	while (i--)
134e68ed793SJohn Baldwin 		free(argv[i]);
135a94a4b74SMark Johnston 	LDD_SETENV("TRACE_LOADED_OBJECTS", "yes", 1);
136e68ed793SJohn Baldwin 	return (rval);
137e68ed793SJohn Baldwin }
138fffd993dSEdwin Groothuis #endif
139b9ae52e3SPaul Richards 
140b9ae52e3SPaul Richards int
141a53809fdSMark Murray main(int argc, char *argv[])
142b9ae52e3SPaul Richards {
143a0d476a9SEdwin Groothuis 	char *fmt1, *fmt2;
144a0d476a9SEdwin Groothuis 	int rval, c, aflag, vflag;
145b9ae52e3SPaul Richards 
14620249943SDavid E. O'Brien 	aflag = vflag = 0;
147a0d476a9SEdwin Groothuis 	fmt1 = fmt2 = NULL;
14820249943SDavid E. O'Brien 
149a0d476a9SEdwin Groothuis 	while ((c = getopt(argc, argv, "af:v")) != -1) {
150b9ae52e3SPaul Richards 		switch (c) {
15120249943SDavid E. O'Brien 		case 'a':
15220249943SDavid E. O'Brien 			aflag++;
15320249943SDavid E. O'Brien 			break;
154d138df61SPeter Wemm 		case 'f':
155a0d476a9SEdwin Groothuis 			if (fmt1 != NULL) {
156a0d476a9SEdwin Groothuis 				if (fmt2 != NULL)
1573e762626SPhilippe Charnier 					errx(1, "too many formats");
158d138df61SPeter Wemm 				fmt2 = optarg;
159d138df61SPeter Wemm 			} else
160d138df61SPeter Wemm 				fmt1 = optarg;
161d138df61SPeter Wemm 			break;
162a0d476a9SEdwin Groothuis 		case 'v':
163a0d476a9SEdwin Groothuis 			vflag++;
164a0d476a9SEdwin Groothuis 			break;
165b9ae52e3SPaul Richards 		default:
166b9ae52e3SPaul Richards 			usage();
167699e1b82SRich Murphey 			/* NOTREACHED */
168b9ae52e3SPaul Richards 		}
169b9ae52e3SPaul Richards 	}
170b9ae52e3SPaul Richards 	argc -= optind;
171b9ae52e3SPaul Richards 	argv += optind;
172b9ae52e3SPaul Richards 
173a0d476a9SEdwin Groothuis 	if (vflag && fmt1 != NULL)
1749731d137SPeter Wemm 		errx(1, "-v may not be used with -f");
1759731d137SPeter Wemm 
176b9ae52e3SPaul Richards 	if (argc <= 0) {
177b9ae52e3SPaul Richards 		usage();
178699e1b82SRich Murphey 		/* NOTREACHED */
179b9ae52e3SPaul Richards 	}
180b9ae52e3SPaul Richards 
18197db68b6SDoug Rabson #ifdef __i386__
1829731d137SPeter Wemm 	if (vflag) {
1839731d137SPeter Wemm 		for (c = 0; c < argc; c++)
1849731d137SPeter Wemm 			dump_file(argv[c]);
1859731d137SPeter Wemm 		exit(error_count == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
1869731d137SPeter Wemm 	}
18797db68b6SDoug Rabson #endif
1889731d137SPeter Wemm 
189699e1b82SRich Murphey 	rval = 0;
190e2daa140SJohn Polstra 	for (; argc > 0; argc--, argv++) {
191d3c1e14bSEdwin Groothuis 		int fd, status, is_shlib, rv, type;
192d3c1e14bSEdwin Groothuis 
193b9ae52e3SPaul Richards 		if ((fd = open(*argv, O_RDONLY, 0)) < 0) {
194699e1b82SRich Murphey 			warn("%s", *argv);
195b9ae52e3SPaul Richards 			rval |= 1;
196b9ae52e3SPaul Richards 			continue;
197b9ae52e3SPaul Richards 		}
198d3c1e14bSEdwin Groothuis 		rv = is_executable(*argv, fd, &is_shlib, &type);
199a0d476a9SEdwin Groothuis 		close(fd);
200d3c1e14bSEdwin Groothuis 		if (rv == 0) {
201c474c6d3SDoug Rabson 			rval |= 1;
202c474c6d3SDoug Rabson 			continue;
203c474c6d3SDoug Rabson 		}
204c474c6d3SDoug Rabson 
205fffd993dSEdwin Groothuis 		switch (type) {
206fffd993dSEdwin Groothuis 		case TYPE_ELF:
207fffd993dSEdwin Groothuis 		case TYPE_AOUT:
208fffd993dSEdwin Groothuis 			break;
2098bd833ffSEdwin Groothuis #if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED)
210fffd993dSEdwin Groothuis 		case TYPE_ELF32:
211e68ed793SJohn Baldwin 			rval |= execldd32(*argv, fmt1, fmt2, aflag, vflag);
212e68ed793SJohn Baldwin 			continue;
213fffd993dSEdwin Groothuis #endif
214fffd993dSEdwin Groothuis 		case TYPE_UNKNOWN:
215fffd993dSEdwin Groothuis 		default:
216fffd993dSEdwin Groothuis 			/*
217fffd993dSEdwin Groothuis 			 * This shouldn't happen unless is_executable()
218fffd993dSEdwin Groothuis 			 * is broken.
219fffd993dSEdwin Groothuis 			 */
220fffd993dSEdwin Groothuis 			errx(EDOOFUS, "unknown executable type");
221fffd993dSEdwin Groothuis 		}
222fffd993dSEdwin Groothuis 
223d3c1e14bSEdwin Groothuis 		/* ld.so magic */
224a94a4b74SMark Johnston 		LDD_SETENV("TRACE_LOADED_OBJECTS", "yes", 1);
225d3c1e14bSEdwin Groothuis 		if (fmt1 != NULL)
226a94a4b74SMark Johnston 			LDD_SETENV("TRACE_LOADED_OBJECTS_FMT1", fmt1, 1);
227d3c1e14bSEdwin Groothuis 		if (fmt2 != NULL)
228a94a4b74SMark Johnston 			LDD_SETENV("TRACE_LOADED_OBJECTS_FMT2", fmt2, 1);
229a0d476a9SEdwin Groothuis 
230a94a4b74SMark Johnston 		LDD_SETENV("TRACE_LOADED_OBJECTS_PROGNAME", *argv, 1);
231a0d476a9SEdwin Groothuis 		if (aflag)
232a94a4b74SMark Johnston 			LDD_SETENV("TRACE_LOADED_OBJECTS_ALL", "1", 1);
23320249943SDavid E. O'Brien 		else if (fmt1 == NULL && fmt2 == NULL)
234d138df61SPeter Wemm 			/* Default formats */
235b9ae52e3SPaul Richards 			printf("%s:\n", *argv);
23609e3d49dSJordan K. Hubbard 		fflush(stdout);
237b9ae52e3SPaul Richards 
238b9ae52e3SPaul Richards 		switch (fork()) {
239b9ae52e3SPaul Richards 		case -1:
240699e1b82SRich Murphey 			err(1, "fork");
241b9ae52e3SPaul Richards 			break;
242b9ae52e3SPaul Richards 		default:
24352122f31SJohn Baldwin 			if (wait(&status) < 0) {
244699e1b82SRich Murphey 				warn("wait");
245699e1b82SRich Murphey 				rval |= 1;
246699e1b82SRich Murphey 			} else if (WIFSIGNALED(status)) {
247a0d476a9SEdwin Groothuis 				fprintf(stderr, "%s: signal %d\n", *argv,
248a0d476a9SEdwin Groothuis 				    WTERMSIG(status));
249b9ae52e3SPaul Richards 				rval |= 1;
25052122f31SJohn Baldwin 			} else if (WIFEXITED(status) &&
25152122f31SJohn Baldwin 			    WEXITSTATUS(status) != 0) {
252a0d476a9SEdwin Groothuis 				fprintf(stderr, "%s: exit status %d\n", *argv,
253a0d476a9SEdwin Groothuis 				    WEXITSTATUS(status));
254b9ae52e3SPaul Richards 				rval |= 1;
255b9ae52e3SPaul Richards 			}
256b9ae52e3SPaul Richards 			break;
257b9ae52e3SPaul Richards 		case 0:
258d1cf9ea2SMaxim Sobolev 			if (is_shlib == 0) {
259fc41545eSMaxim Sobolev 				execl(*argv, *argv, (char *)NULL);
2603e762626SPhilippe Charnier 				warn("%s", *argv);
261d1cf9ea2SMaxim Sobolev 			} else {
262d1cf9ea2SMaxim Sobolev 				dlopen(*argv, RTLD_TRACE);
263d1cf9ea2SMaxim Sobolev 				warnx("%s: %s", *argv, dlerror());
264c6de4ce7SMaxim Sobolev 			}
265b9ae52e3SPaul Richards 			_exit(1);
266b9ae52e3SPaul Richards 		}
267b9ae52e3SPaul Richards 	}
268b9ae52e3SPaul Richards 
269b9ae52e3SPaul Richards 	return rval;
270b9ae52e3SPaul Richards }
271d3c1e14bSEdwin Groothuis 
272d3c1e14bSEdwin Groothuis static void
273d3c1e14bSEdwin Groothuis usage(void)
274d3c1e14bSEdwin Groothuis {
275d3c1e14bSEdwin Groothuis 
276d3c1e14bSEdwin Groothuis 	fprintf(stderr, "usage: ldd [-a] [-v] [-f format] program ...\n");
277d3c1e14bSEdwin Groothuis 	exit(1);
278d3c1e14bSEdwin Groothuis }
279d3c1e14bSEdwin Groothuis 
280d3c1e14bSEdwin Groothuis static int
281d3c1e14bSEdwin Groothuis is_executable(const char *fname, int fd, int *is_shlib, int *type)
282d3c1e14bSEdwin Groothuis {
283d3c1e14bSEdwin Groothuis 	union {
284e1f65999SAndrew Turner #ifdef AOUT_SUPPORTED
285d3c1e14bSEdwin Groothuis 		struct exec aout;
286e1f65999SAndrew Turner #endif
2878bd833ffSEdwin Groothuis #if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED)
288fffd993dSEdwin Groothuis 		Elf32_Ehdr elf32;
2898bd833ffSEdwin Groothuis #endif
290d3c1e14bSEdwin Groothuis 		Elf_Ehdr elf;
291d3c1e14bSEdwin Groothuis 	} hdr;
292*2b5d88fdSKonstantin Belousov 	Elf_Phdr phdr, dynphdr;
293*2b5d88fdSKonstantin Belousov 	Elf_Dyn *dynp;
294*2b5d88fdSKonstantin Belousov 	void *dyndata;
295*2b5d88fdSKonstantin Belousov #if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED)
296*2b5d88fdSKonstantin Belousov 	Elf32_Phdr phdr32, dynphdr32;
297*2b5d88fdSKonstantin Belousov 	Elf32_Dyn *dynp32;
298*2b5d88fdSKonstantin Belousov #endif
299*2b5d88fdSKonstantin Belousov 	int df1pie, dynamic, i, n;
300d3c1e14bSEdwin Groothuis 
301d3c1e14bSEdwin Groothuis 	*is_shlib = 0;
302d3c1e14bSEdwin Groothuis 	*type = TYPE_UNKNOWN;
303*2b5d88fdSKonstantin Belousov 	df1pie = 0;
304d3c1e14bSEdwin Groothuis 
305d3c1e14bSEdwin Groothuis 	if ((n = read(fd, &hdr, sizeof(hdr))) == -1) {
306d3c1e14bSEdwin Groothuis 		warn("%s: can't read program header", fname);
307d3c1e14bSEdwin Groothuis 		return (0);
308d3c1e14bSEdwin Groothuis 	}
309d3c1e14bSEdwin Groothuis 
310e1f65999SAndrew Turner #ifdef AOUT_SUPPORTED
311d3c1e14bSEdwin Groothuis 	if ((size_t)n >= sizeof(hdr.aout) && !N_BADMAG(hdr.aout)) {
312d3c1e14bSEdwin Groothuis 		/* a.out file */
313d3c1e14bSEdwin Groothuis 		if ((N_GETFLAG(hdr.aout) & EX_DPMASK) != EX_DYNAMIC
314d3c1e14bSEdwin Groothuis #if 1 /* Compatibility */
315d3c1e14bSEdwin Groothuis 		    || hdr.aout.a_entry < __LDPGSZ
316d3c1e14bSEdwin Groothuis #endif
317d3c1e14bSEdwin Groothuis 			) {
318d3c1e14bSEdwin Groothuis 			warnx("%s: not a dynamic executable", fname);
319d3c1e14bSEdwin Groothuis 			return (0);
320d3c1e14bSEdwin Groothuis 		}
321d3c1e14bSEdwin Groothuis 		*type = TYPE_AOUT;
3225a2c0ab1SEd Maste 		warnx("%s: aout support is deprecated", fname);
323d3c1e14bSEdwin Groothuis 		return (1);
324d3c1e14bSEdwin Groothuis 	}
325e1f65999SAndrew Turner #endif
326d3c1e14bSEdwin Groothuis 
3278bd833ffSEdwin Groothuis #if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED)
328fffd993dSEdwin Groothuis 	if ((size_t)n >= sizeof(hdr.elf32) && IS_ELF(hdr.elf32) &&
329fffd993dSEdwin Groothuis 	    hdr.elf32.e_ident[EI_CLASS] == ELFCLASS32) {
330fffd993dSEdwin Groothuis 		/* Handle 32 bit ELF objects */
331fffd993dSEdwin Groothuis 
332fffd993dSEdwin Groothuis 		dynamic = 0;
333fffd993dSEdwin Groothuis 		*type = TYPE_ELF32;
334fffd993dSEdwin Groothuis 
335fffd993dSEdwin Groothuis 		if (lseek(fd, hdr.elf32.e_phoff, SEEK_SET) == -1) {
336fffd993dSEdwin Groothuis 			warnx("%s: header too short", fname);
337fffd993dSEdwin Groothuis 			return (0);
338fffd993dSEdwin Groothuis 		}
339fffd993dSEdwin Groothuis 		for (i = 0; i < hdr.elf32.e_phnum; i++) {
340*2b5d88fdSKonstantin Belousov 			if (read(fd, &phdr32, hdr.elf32.e_phentsize) !=
341*2b5d88fdSKonstantin Belousov 			    sizeof(phdr32)) {
342fffd993dSEdwin Groothuis 				warnx("%s: can't read program header", fname);
343fffd993dSEdwin Groothuis 				return (0);
344fffd993dSEdwin Groothuis 			}
345*2b5d88fdSKonstantin Belousov 			if (phdr32.p_type == PT_DYNAMIC) {
346fffd993dSEdwin Groothuis 				dynamic = 1;
347*2b5d88fdSKonstantin Belousov 				dynphdr32 = phdr32;
348fffd993dSEdwin Groothuis 				break;
349fffd993dSEdwin Groothuis 			}
350fffd993dSEdwin Groothuis 		}
351fffd993dSEdwin Groothuis 
352fffd993dSEdwin Groothuis 		if (!dynamic) {
353fffd993dSEdwin Groothuis 			warnx("%s: not a dynamic ELF executable", fname);
354fffd993dSEdwin Groothuis 			return (0);
355fffd993dSEdwin Groothuis 		}
356*2b5d88fdSKonstantin Belousov 
357fffd993dSEdwin Groothuis 		if (hdr.elf32.e_type == ET_DYN) {
358*2b5d88fdSKonstantin Belousov 			if (lseek(fd, dynphdr32.p_offset, SEEK_SET) == -1) {
359*2b5d88fdSKonstantin Belousov 				warnx("%s: dynamic segment out of range",
360*2b5d88fdSKonstantin Belousov 				    fname);
361*2b5d88fdSKonstantin Belousov 				return (0);
362*2b5d88fdSKonstantin Belousov 			}
363*2b5d88fdSKonstantin Belousov 			dyndata = malloc(dynphdr32.p_filesz);
364*2b5d88fdSKonstantin Belousov 			if (dyndata == NULL) {
365*2b5d88fdSKonstantin Belousov 				warn("malloc");
366*2b5d88fdSKonstantin Belousov 				return (0);
367*2b5d88fdSKonstantin Belousov 			}
368*2b5d88fdSKonstantin Belousov 			if (read(fd, dyndata, dynphdr32.p_filesz) !=
369*2b5d88fdSKonstantin Belousov 			    (ssize_t)dynphdr32.p_filesz) {
370*2b5d88fdSKonstantin Belousov 				free(dyndata);
371*2b5d88fdSKonstantin Belousov 				warnx("%s: can't read dynamic segment", fname);
372*2b5d88fdSKonstantin Belousov 				return (0);
373*2b5d88fdSKonstantin Belousov 			}
374*2b5d88fdSKonstantin Belousov 			for (dynp32 = dyndata; dynp32->d_tag != DT_NULL;
375*2b5d88fdSKonstantin Belousov 			    dynp32++) {
376*2b5d88fdSKonstantin Belousov 				if (dynp32->d_tag != DT_FLAGS_1)
377*2b5d88fdSKonstantin Belousov 					continue;
378*2b5d88fdSKonstantin Belousov 				df1pie = (dynp32->d_un.d_val & DF_1_PIE) != 0;
379*2b5d88fdSKonstantin Belousov 				break;
380*2b5d88fdSKonstantin Belousov 			}
381*2b5d88fdSKonstantin Belousov 			free(dyndata);
382*2b5d88fdSKonstantin Belousov 
38370557f4fSRebecca Cran 			if (hdr.elf32.e_ident[EI_OSABI] == ELFOSABI_FREEBSD) {
384*2b5d88fdSKonstantin Belousov 				if (!df1pie)
385fffd993dSEdwin Groothuis 					*is_shlib = 1;
386fffd993dSEdwin Groothuis 				return (1);
387fffd993dSEdwin Groothuis 			}
388fffd993dSEdwin Groothuis 			warnx("%s: not a FreeBSD ELF shared object", fname);
389fffd993dSEdwin Groothuis 			return (0);
390fffd993dSEdwin Groothuis 		}
391fffd993dSEdwin Groothuis 
392fffd993dSEdwin Groothuis 		return (1);
393fffd993dSEdwin Groothuis 	}
394fffd993dSEdwin Groothuis #endif
395fffd993dSEdwin Groothuis 
396d3c1e14bSEdwin Groothuis 	if ((size_t)n >= sizeof(hdr.elf) && IS_ELF(hdr.elf) &&
397d3c1e14bSEdwin Groothuis 	    hdr.elf.e_ident[EI_CLASS] == ELF_TARG_CLASS) {
398d3c1e14bSEdwin Groothuis 		/* Handle default ELF objects on this architecture */
399d3c1e14bSEdwin Groothuis 
400d3c1e14bSEdwin Groothuis 		dynamic = 0;
401d3c1e14bSEdwin Groothuis 		*type = TYPE_ELF;
402d3c1e14bSEdwin Groothuis 
403d3c1e14bSEdwin Groothuis 		if (lseek(fd, hdr.elf.e_phoff, SEEK_SET) == -1) {
404d3c1e14bSEdwin Groothuis 			warnx("%s: header too short", fname);
405d3c1e14bSEdwin Groothuis 			return (0);
406d3c1e14bSEdwin Groothuis 		}
407d3c1e14bSEdwin Groothuis 		for (i = 0; i < hdr.elf.e_phnum; i++) {
408d3c1e14bSEdwin Groothuis 			if (read(fd, &phdr, hdr.elf.e_phentsize)
409d3c1e14bSEdwin Groothuis 			   != sizeof(phdr)) {
410d3c1e14bSEdwin Groothuis 				warnx("%s: can't read program header", fname);
411d3c1e14bSEdwin Groothuis 				return (0);
412d3c1e14bSEdwin Groothuis 			}
413d3c1e14bSEdwin Groothuis 			if (phdr.p_type == PT_DYNAMIC) {
414d3c1e14bSEdwin Groothuis 				dynamic = 1;
415*2b5d88fdSKonstantin Belousov 				dynphdr = phdr;
416d3c1e14bSEdwin Groothuis 				break;
417d3c1e14bSEdwin Groothuis 			}
418d3c1e14bSEdwin Groothuis 		}
419d3c1e14bSEdwin Groothuis 
420d3c1e14bSEdwin Groothuis 		if (!dynamic) {
421d3c1e14bSEdwin Groothuis 			warnx("%s: not a dynamic ELF executable", fname);
422d3c1e14bSEdwin Groothuis 			return (0);
423d3c1e14bSEdwin Groothuis 		}
424*2b5d88fdSKonstantin Belousov 
425d3c1e14bSEdwin Groothuis 		if (hdr.elf.e_type == ET_DYN) {
426*2b5d88fdSKonstantin Belousov 			if (lseek(fd, dynphdr.p_offset, SEEK_SET) == -1) {
427*2b5d88fdSKonstantin Belousov 				warnx("%s: dynamic segment out of range",
428*2b5d88fdSKonstantin Belousov 				    fname);
429*2b5d88fdSKonstantin Belousov 				return (0);
430*2b5d88fdSKonstantin Belousov 			}
431*2b5d88fdSKonstantin Belousov 			dyndata = malloc(dynphdr.p_filesz);
432*2b5d88fdSKonstantin Belousov 			if (dyndata == NULL) {
433*2b5d88fdSKonstantin Belousov 				warn("malloc");
434*2b5d88fdSKonstantin Belousov 				return (0);
435*2b5d88fdSKonstantin Belousov 			}
436*2b5d88fdSKonstantin Belousov 			if (read(fd, dyndata, dynphdr.p_filesz) !=
437*2b5d88fdSKonstantin Belousov 			    (ssize_t)dynphdr.p_filesz) {
438*2b5d88fdSKonstantin Belousov 				free(dyndata);
439*2b5d88fdSKonstantin Belousov 				warnx("%s: can't read dynamic segment", fname);
440*2b5d88fdSKonstantin Belousov 				return (0);
441*2b5d88fdSKonstantin Belousov 			}
442*2b5d88fdSKonstantin Belousov 			for (dynp = dyndata; dynp->d_tag != DT_NULL; dynp++) {
443*2b5d88fdSKonstantin Belousov 				if (dynp->d_tag != DT_FLAGS_1)
444*2b5d88fdSKonstantin Belousov 					continue;
445*2b5d88fdSKonstantin Belousov 				df1pie = (dynp->d_un.d_val & DF_1_PIE) != 0;
446*2b5d88fdSKonstantin Belousov 				break;
447*2b5d88fdSKonstantin Belousov 			}
448*2b5d88fdSKonstantin Belousov 			free(dyndata);
449*2b5d88fdSKonstantin Belousov 
450a41dab8fSJung-uk Kim 			switch (hdr.elf.e_ident[EI_OSABI]) {
451a41dab8fSJung-uk Kim 			case ELFOSABI_FREEBSD:
452*2b5d88fdSKonstantin Belousov 				if (!df1pie)
453d3c1e14bSEdwin Groothuis 					*is_shlib = 1;
454d3c1e14bSEdwin Groothuis 				return (1);
455a41dab8fSJung-uk Kim #ifdef __ARM_EABI__
456a41dab8fSJung-uk Kim 			case ELFOSABI_NONE:
457a41dab8fSJung-uk Kim 				if (hdr.elf.e_machine != EM_ARM)
458a41dab8fSJung-uk Kim 					break;
459a41dab8fSJung-uk Kim 				if (EF_ARM_EABI_VERSION(hdr.elf.e_flags) <
460a41dab8fSJung-uk Kim 				    EF_ARM_EABI_FREEBSD_MIN)
461a41dab8fSJung-uk Kim 					break;
462a41dab8fSJung-uk Kim 				*is_shlib = 1;
463a41dab8fSJung-uk Kim 				return (1);
464a41dab8fSJung-uk Kim #endif
465d3c1e14bSEdwin Groothuis 			}
466d3c1e14bSEdwin Groothuis 			warnx("%s: not a FreeBSD ELF shared object", fname);
467d3c1e14bSEdwin Groothuis 			return (0);
468d3c1e14bSEdwin Groothuis 		}
469d3c1e14bSEdwin Groothuis 
470d3c1e14bSEdwin Groothuis 		return (1);
471d3c1e14bSEdwin Groothuis 	}
472d3c1e14bSEdwin Groothuis 
473d3c1e14bSEdwin Groothuis 	warnx("%s: not a dynamic executable", fname);
474d3c1e14bSEdwin Groothuis 	return (0);
475d3c1e14bSEdwin Groothuis }
476