xref: /freebsd/usr.bin/ldd/ldd.c (revision c8eee7c0bf9a01303c75b4c3ac644b99adc70ca9)
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 
518bd833ffSEdwin Groothuis /*
52bff71350SEdwin Groothuis  * 32-bit ELF data structures can only be used if the system header[s] declare
53bff71350SEdwin Groothuis  * them.  There is no official macro for determining whether they are declared,
54bff71350SEdwin Groothuis  * so check for the existence of one of the 32-macros defined in elf(5).
558bd833ffSEdwin Groothuis  */
56bff71350SEdwin Groothuis #ifdef ELF32_R_TYPE
578bd833ffSEdwin Groothuis #define	ELF32_SUPPORTED
588bd833ffSEdwin Groothuis #endif
598bd833ffSEdwin Groothuis 
60a94a4b74SMark Johnston #define	LDD_SETENV(name, value, overwrite) do {		\
61a94a4b74SMark Johnston 	setenv("LD_" name, value, overwrite);		\
62a94a4b74SMark Johnston 	setenv("LD_32_" name, value, overwrite);	\
63a94a4b74SMark Johnston } while (0)
64a94a4b74SMark Johnston 
65a94a4b74SMark Johnston #define	LDD_UNSETENV(name) do {		\
66a94a4b74SMark Johnston 	unsetenv("LD_" name);		\
67a94a4b74SMark Johnston 	unsetenv("LD_32_" name);	\
68a94a4b74SMark Johnston } while (0)
69a94a4b74SMark Johnston 
70d3c1e14bSEdwin Groothuis static int	is_executable(const char *fname, int fd, int *is_shlib,
71d3c1e14bSEdwin Groothuis 		    int *type);
72d3c1e14bSEdwin Groothuis static void	usage(void);
73a0d476a9SEdwin Groothuis 
74d3c1e14bSEdwin Groothuis #define	TYPE_UNKNOWN	0
75*c8eee7c0SEd Maste #define	TYPE_ELF	1	/* Architecture default */
768bd833ffSEdwin Groothuis #if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED)
77*c8eee7c0SEd Maste #define	TYPE_ELF32	2	/* Explicit 32 bits on architectures >32 bits */
78d3c1e14bSEdwin Groothuis 
79e68ed793SJohn Baldwin #define	_PATH_LDD32	"/usr/bin/ldd32"
80d3c1e14bSEdwin Groothuis 
81e68ed793SJohn Baldwin static int
82e68ed793SJohn Baldwin execldd32(char *file, char *fmt1, char *fmt2, int aflag, int vflag)
83e68ed793SJohn Baldwin {
844b426307SDon Lewis 	char *argv[9];
85e68ed793SJohn Baldwin 	int i, rval, status;
86e68ed793SJohn Baldwin 
87a94a4b74SMark Johnston 	LDD_UNSETENV("TRACE_LOADED_OBJECTS");
88e68ed793SJohn Baldwin 	rval = 0;
89e68ed793SJohn Baldwin 	i = 0;
90e68ed793SJohn Baldwin 	argv[i++] = strdup(_PATH_LDD32);
91e68ed793SJohn Baldwin 	if (aflag)
92e68ed793SJohn Baldwin 		argv[i++] = strdup("-a");
93e68ed793SJohn Baldwin 	if (vflag)
94e68ed793SJohn Baldwin 		argv[i++] = strdup("-v");
9552122f31SJohn Baldwin 	if (fmt1 != NULL) {
96e68ed793SJohn Baldwin 		argv[i++] = strdup("-f");
97e68ed793SJohn Baldwin 		argv[i++] = strdup(fmt1);
98e68ed793SJohn Baldwin 	}
9952122f31SJohn Baldwin 	if (fmt2 != NULL) {
100e68ed793SJohn Baldwin 		argv[i++] = strdup("-f");
101e68ed793SJohn Baldwin 		argv[i++] = strdup(fmt2);
102e68ed793SJohn Baldwin 	}
103e68ed793SJohn Baldwin 	argv[i++] = strdup(file);
104e68ed793SJohn Baldwin 	argv[i++] = NULL;
105e68ed793SJohn Baldwin 
106e68ed793SJohn Baldwin 	switch (fork()) {
107e68ed793SJohn Baldwin 	case -1:
108e68ed793SJohn Baldwin 		err(1, "fork");
109e68ed793SJohn Baldwin 		break;
110e68ed793SJohn Baldwin 	case 0:
111e68ed793SJohn Baldwin 		execv(_PATH_LDD32, argv);
112e68ed793SJohn Baldwin 		warn("%s", _PATH_LDD32);
11352122f31SJohn Baldwin 		_exit(127);
114e68ed793SJohn Baldwin 		break;
115e68ed793SJohn Baldwin 	default:
11652122f31SJohn Baldwin 		if (wait(&status) < 0)
117e68ed793SJohn Baldwin 			rval = 1;
11852122f31SJohn Baldwin 		else if (WIFSIGNALED(status))
119e68ed793SJohn Baldwin 			rval = 1;
12052122f31SJohn Baldwin 		else if (WIFEXITED(status) && WEXITSTATUS(status) != 0)
121e68ed793SJohn Baldwin 			rval = 1;
122e68ed793SJohn Baldwin 		break;
123e68ed793SJohn Baldwin 	}
124e68ed793SJohn Baldwin 	while (i--)
125e68ed793SJohn Baldwin 		free(argv[i]);
126a94a4b74SMark Johnston 	LDD_SETENV("TRACE_LOADED_OBJECTS", "yes", 1);
127e68ed793SJohn Baldwin 	return (rval);
128e68ed793SJohn Baldwin }
129fffd993dSEdwin Groothuis #endif
130b9ae52e3SPaul Richards 
131b9ae52e3SPaul Richards int
132a53809fdSMark Murray main(int argc, char *argv[])
133b9ae52e3SPaul Richards {
134a0d476a9SEdwin Groothuis 	char *fmt1, *fmt2;
135a0d476a9SEdwin Groothuis 	int rval, c, aflag, vflag;
136b9ae52e3SPaul Richards 
13720249943SDavid E. O'Brien 	aflag = vflag = 0;
138a0d476a9SEdwin Groothuis 	fmt1 = fmt2 = NULL;
13920249943SDavid E. O'Brien 
140a0d476a9SEdwin Groothuis 	while ((c = getopt(argc, argv, "af:v")) != -1) {
141b9ae52e3SPaul Richards 		switch (c) {
14220249943SDavid E. O'Brien 		case 'a':
14320249943SDavid E. O'Brien 			aflag++;
14420249943SDavid E. O'Brien 			break;
145d138df61SPeter Wemm 		case 'f':
146a0d476a9SEdwin Groothuis 			if (fmt1 != NULL) {
147a0d476a9SEdwin Groothuis 				if (fmt2 != NULL)
1483e762626SPhilippe Charnier 					errx(1, "too many formats");
149d138df61SPeter Wemm 				fmt2 = optarg;
150d138df61SPeter Wemm 			} else
151d138df61SPeter Wemm 				fmt1 = optarg;
152d138df61SPeter Wemm 			break;
153a0d476a9SEdwin Groothuis 		case 'v':
154a0d476a9SEdwin Groothuis 			vflag++;
155a0d476a9SEdwin Groothuis 			break;
156b9ae52e3SPaul Richards 		default:
157b9ae52e3SPaul Richards 			usage();
158699e1b82SRich Murphey 			/* NOTREACHED */
159b9ae52e3SPaul Richards 		}
160b9ae52e3SPaul Richards 	}
161b9ae52e3SPaul Richards 	argc -= optind;
162b9ae52e3SPaul Richards 	argv += optind;
163b9ae52e3SPaul Richards 
164a0d476a9SEdwin Groothuis 	if (vflag && fmt1 != NULL)
1659731d137SPeter Wemm 		errx(1, "-v may not be used with -f");
1669731d137SPeter Wemm 
167b9ae52e3SPaul Richards 	if (argc <= 0) {
168b9ae52e3SPaul Richards 		usage();
169699e1b82SRich Murphey 		/* NOTREACHED */
170b9ae52e3SPaul Richards 	}
171b9ae52e3SPaul Richards 
172699e1b82SRich Murphey 	rval = 0;
173e2daa140SJohn Polstra 	for (; argc > 0; argc--, argv++) {
174d3c1e14bSEdwin Groothuis 		int fd, status, is_shlib, rv, type;
175d3c1e14bSEdwin Groothuis 
176b9ae52e3SPaul Richards 		if ((fd = open(*argv, O_RDONLY, 0)) < 0) {
177699e1b82SRich Murphey 			warn("%s", *argv);
178b9ae52e3SPaul Richards 			rval |= 1;
179b9ae52e3SPaul Richards 			continue;
180b9ae52e3SPaul Richards 		}
181d3c1e14bSEdwin Groothuis 		rv = is_executable(*argv, fd, &is_shlib, &type);
182a0d476a9SEdwin Groothuis 		close(fd);
183d3c1e14bSEdwin Groothuis 		if (rv == 0) {
184c474c6d3SDoug Rabson 			rval |= 1;
185c474c6d3SDoug Rabson 			continue;
186c474c6d3SDoug Rabson 		}
187c474c6d3SDoug Rabson 
188fffd993dSEdwin Groothuis 		switch (type) {
189fffd993dSEdwin Groothuis 		case TYPE_ELF:
190fffd993dSEdwin Groothuis 			break;
1918bd833ffSEdwin Groothuis #if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED)
192fffd993dSEdwin Groothuis 		case TYPE_ELF32:
193e68ed793SJohn Baldwin 			rval |= execldd32(*argv, fmt1, fmt2, aflag, vflag);
194e68ed793SJohn Baldwin 			continue;
195fffd993dSEdwin Groothuis #endif
196fffd993dSEdwin Groothuis 		case TYPE_UNKNOWN:
197fffd993dSEdwin Groothuis 		default:
198fffd993dSEdwin Groothuis 			/*
199fffd993dSEdwin Groothuis 			 * This shouldn't happen unless is_executable()
200fffd993dSEdwin Groothuis 			 * is broken.
201fffd993dSEdwin Groothuis 			 */
202fffd993dSEdwin Groothuis 			errx(EDOOFUS, "unknown executable type");
203fffd993dSEdwin Groothuis 		}
204fffd993dSEdwin Groothuis 
205d3c1e14bSEdwin Groothuis 		/* ld.so magic */
206a94a4b74SMark Johnston 		LDD_SETENV("TRACE_LOADED_OBJECTS", "yes", 1);
207d3c1e14bSEdwin Groothuis 		if (fmt1 != NULL)
208a94a4b74SMark Johnston 			LDD_SETENV("TRACE_LOADED_OBJECTS_FMT1", fmt1, 1);
209d3c1e14bSEdwin Groothuis 		if (fmt2 != NULL)
210a94a4b74SMark Johnston 			LDD_SETENV("TRACE_LOADED_OBJECTS_FMT2", fmt2, 1);
211a0d476a9SEdwin Groothuis 
212a94a4b74SMark Johnston 		LDD_SETENV("TRACE_LOADED_OBJECTS_PROGNAME", *argv, 1);
213a0d476a9SEdwin Groothuis 		if (aflag)
214a94a4b74SMark Johnston 			LDD_SETENV("TRACE_LOADED_OBJECTS_ALL", "1", 1);
21520249943SDavid E. O'Brien 		else if (fmt1 == NULL && fmt2 == NULL)
216d138df61SPeter Wemm 			/* Default formats */
217b9ae52e3SPaul Richards 			printf("%s:\n", *argv);
21809e3d49dSJordan K. Hubbard 		fflush(stdout);
219b9ae52e3SPaul Richards 
220b9ae52e3SPaul Richards 		switch (fork()) {
221b9ae52e3SPaul Richards 		case -1:
222699e1b82SRich Murphey 			err(1, "fork");
223b9ae52e3SPaul Richards 			break;
224b9ae52e3SPaul Richards 		default:
22552122f31SJohn Baldwin 			if (wait(&status) < 0) {
226699e1b82SRich Murphey 				warn("wait");
227699e1b82SRich Murphey 				rval |= 1;
228699e1b82SRich Murphey 			} else if (WIFSIGNALED(status)) {
229a0d476a9SEdwin Groothuis 				fprintf(stderr, "%s: signal %d\n", *argv,
230a0d476a9SEdwin Groothuis 				    WTERMSIG(status));
231b9ae52e3SPaul Richards 				rval |= 1;
23252122f31SJohn Baldwin 			} else if (WIFEXITED(status) &&
23352122f31SJohn Baldwin 			    WEXITSTATUS(status) != 0) {
234a0d476a9SEdwin Groothuis 				fprintf(stderr, "%s: exit status %d\n", *argv,
235a0d476a9SEdwin Groothuis 				    WEXITSTATUS(status));
236b9ae52e3SPaul Richards 				rval |= 1;
237b9ae52e3SPaul Richards 			}
238b9ae52e3SPaul Richards 			break;
239b9ae52e3SPaul Richards 		case 0:
240d1cf9ea2SMaxim Sobolev 			if (is_shlib == 0) {
241fc41545eSMaxim Sobolev 				execl(*argv, *argv, (char *)NULL);
2423e762626SPhilippe Charnier 				warn("%s", *argv);
243d1cf9ea2SMaxim Sobolev 			} else {
244d1cf9ea2SMaxim Sobolev 				dlopen(*argv, RTLD_TRACE);
245d1cf9ea2SMaxim Sobolev 				warnx("%s: %s", *argv, dlerror());
246c6de4ce7SMaxim Sobolev 			}
247b9ae52e3SPaul Richards 			_exit(1);
248b9ae52e3SPaul Richards 		}
249b9ae52e3SPaul Richards 	}
250b9ae52e3SPaul Richards 
251b9ae52e3SPaul Richards 	return rval;
252b9ae52e3SPaul Richards }
253d3c1e14bSEdwin Groothuis 
254d3c1e14bSEdwin Groothuis static void
255d3c1e14bSEdwin Groothuis usage(void)
256d3c1e14bSEdwin Groothuis {
257d3c1e14bSEdwin Groothuis 
258d3c1e14bSEdwin Groothuis 	fprintf(stderr, "usage: ldd [-a] [-v] [-f format] program ...\n");
259d3c1e14bSEdwin Groothuis 	exit(1);
260d3c1e14bSEdwin Groothuis }
261d3c1e14bSEdwin Groothuis 
262d3c1e14bSEdwin Groothuis static int
263d3c1e14bSEdwin Groothuis is_executable(const char *fname, int fd, int *is_shlib, int *type)
264d3c1e14bSEdwin Groothuis {
265d3c1e14bSEdwin Groothuis 	union {
2668bd833ffSEdwin Groothuis #if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED)
267fffd993dSEdwin Groothuis 		Elf32_Ehdr elf32;
2688bd833ffSEdwin Groothuis #endif
269d3c1e14bSEdwin Groothuis 		Elf_Ehdr elf;
270d3c1e14bSEdwin Groothuis 	} hdr;
2712b5d88fdSKonstantin Belousov 	Elf_Phdr phdr, dynphdr;
2722b5d88fdSKonstantin Belousov 	Elf_Dyn *dynp;
2732b5d88fdSKonstantin Belousov 	void *dyndata;
2742b5d88fdSKonstantin Belousov #if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED)
2752b5d88fdSKonstantin Belousov 	Elf32_Phdr phdr32, dynphdr32;
2762b5d88fdSKonstantin Belousov 	Elf32_Dyn *dynp32;
2772b5d88fdSKonstantin Belousov #endif
2782b5d88fdSKonstantin Belousov 	int df1pie, dynamic, i, n;
279d3c1e14bSEdwin Groothuis 
280d3c1e14bSEdwin Groothuis 	*is_shlib = 0;
281d3c1e14bSEdwin Groothuis 	*type = TYPE_UNKNOWN;
2822b5d88fdSKonstantin Belousov 	df1pie = 0;
283d3c1e14bSEdwin Groothuis 
284d3c1e14bSEdwin Groothuis 	if ((n = read(fd, &hdr, sizeof(hdr))) == -1) {
285d3c1e14bSEdwin Groothuis 		warn("%s: can't read program header", fname);
286d3c1e14bSEdwin Groothuis 		return (0);
287d3c1e14bSEdwin Groothuis 	}
288d3c1e14bSEdwin Groothuis 
2898bd833ffSEdwin Groothuis #if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED)
290fffd993dSEdwin Groothuis 	if ((size_t)n >= sizeof(hdr.elf32) && IS_ELF(hdr.elf32) &&
291fffd993dSEdwin Groothuis 	    hdr.elf32.e_ident[EI_CLASS] == ELFCLASS32) {
292fffd993dSEdwin Groothuis 		/* Handle 32 bit ELF objects */
293fffd993dSEdwin Groothuis 
294fffd993dSEdwin Groothuis 		dynamic = 0;
295fffd993dSEdwin Groothuis 		*type = TYPE_ELF32;
296fffd993dSEdwin Groothuis 
297fffd993dSEdwin Groothuis 		if (lseek(fd, hdr.elf32.e_phoff, SEEK_SET) == -1) {
298fffd993dSEdwin Groothuis 			warnx("%s: header too short", fname);
299fffd993dSEdwin Groothuis 			return (0);
300fffd993dSEdwin Groothuis 		}
301fffd993dSEdwin Groothuis 		for (i = 0; i < hdr.elf32.e_phnum; i++) {
3022b5d88fdSKonstantin Belousov 			if (read(fd, &phdr32, hdr.elf32.e_phentsize) !=
3032b5d88fdSKonstantin Belousov 			    sizeof(phdr32)) {
304fffd993dSEdwin Groothuis 				warnx("%s: can't read program header", fname);
305fffd993dSEdwin Groothuis 				return (0);
306fffd993dSEdwin Groothuis 			}
3072b5d88fdSKonstantin Belousov 			if (phdr32.p_type == PT_DYNAMIC) {
308fffd993dSEdwin Groothuis 				dynamic = 1;
3092b5d88fdSKonstantin Belousov 				dynphdr32 = phdr32;
310fffd993dSEdwin Groothuis 				break;
311fffd993dSEdwin Groothuis 			}
312fffd993dSEdwin Groothuis 		}
313fffd993dSEdwin Groothuis 
314fffd993dSEdwin Groothuis 		if (!dynamic) {
315fffd993dSEdwin Groothuis 			warnx("%s: not a dynamic ELF executable", fname);
316fffd993dSEdwin Groothuis 			return (0);
317fffd993dSEdwin Groothuis 		}
3182b5d88fdSKonstantin Belousov 
319fffd993dSEdwin Groothuis 		if (hdr.elf32.e_type == ET_DYN) {
3202b5d88fdSKonstantin Belousov 			if (lseek(fd, dynphdr32.p_offset, SEEK_SET) == -1) {
3212b5d88fdSKonstantin Belousov 				warnx("%s: dynamic segment out of range",
3222b5d88fdSKonstantin Belousov 				    fname);
3232b5d88fdSKonstantin Belousov 				return (0);
3242b5d88fdSKonstantin Belousov 			}
3252b5d88fdSKonstantin Belousov 			dyndata = malloc(dynphdr32.p_filesz);
3262b5d88fdSKonstantin Belousov 			if (dyndata == NULL) {
3272b5d88fdSKonstantin Belousov 				warn("malloc");
3282b5d88fdSKonstantin Belousov 				return (0);
3292b5d88fdSKonstantin Belousov 			}
3302b5d88fdSKonstantin Belousov 			if (read(fd, dyndata, dynphdr32.p_filesz) !=
3312b5d88fdSKonstantin Belousov 			    (ssize_t)dynphdr32.p_filesz) {
3322b5d88fdSKonstantin Belousov 				free(dyndata);
3332b5d88fdSKonstantin Belousov 				warnx("%s: can't read dynamic segment", fname);
3342b5d88fdSKonstantin Belousov 				return (0);
3352b5d88fdSKonstantin Belousov 			}
3362b5d88fdSKonstantin Belousov 			for (dynp32 = dyndata; dynp32->d_tag != DT_NULL;
3372b5d88fdSKonstantin Belousov 			    dynp32++) {
3382b5d88fdSKonstantin Belousov 				if (dynp32->d_tag != DT_FLAGS_1)
3392b5d88fdSKonstantin Belousov 					continue;
3402b5d88fdSKonstantin Belousov 				df1pie = (dynp32->d_un.d_val & DF_1_PIE) != 0;
3412b5d88fdSKonstantin Belousov 				break;
3422b5d88fdSKonstantin Belousov 			}
3432b5d88fdSKonstantin Belousov 			free(dyndata);
3442b5d88fdSKonstantin Belousov 
34570557f4fSRebecca Cran 			if (hdr.elf32.e_ident[EI_OSABI] == ELFOSABI_FREEBSD) {
3462b5d88fdSKonstantin Belousov 				if (!df1pie)
347fffd993dSEdwin Groothuis 					*is_shlib = 1;
348fffd993dSEdwin Groothuis 				return (1);
349fffd993dSEdwin Groothuis 			}
350fffd993dSEdwin Groothuis 			warnx("%s: not a FreeBSD ELF shared object", fname);
351fffd993dSEdwin Groothuis 			return (0);
352fffd993dSEdwin Groothuis 		}
353fffd993dSEdwin Groothuis 
354fffd993dSEdwin Groothuis 		return (1);
355fffd993dSEdwin Groothuis 	}
356fffd993dSEdwin Groothuis #endif
357fffd993dSEdwin Groothuis 
358d3c1e14bSEdwin Groothuis 	if ((size_t)n >= sizeof(hdr.elf) && IS_ELF(hdr.elf) &&
359d3c1e14bSEdwin Groothuis 	    hdr.elf.e_ident[EI_CLASS] == ELF_TARG_CLASS) {
360d3c1e14bSEdwin Groothuis 		/* Handle default ELF objects on this architecture */
361d3c1e14bSEdwin Groothuis 
362d3c1e14bSEdwin Groothuis 		dynamic = 0;
363d3c1e14bSEdwin Groothuis 		*type = TYPE_ELF;
364d3c1e14bSEdwin Groothuis 
365d3c1e14bSEdwin Groothuis 		if (lseek(fd, hdr.elf.e_phoff, SEEK_SET) == -1) {
366d3c1e14bSEdwin Groothuis 			warnx("%s: header too short", fname);
367d3c1e14bSEdwin Groothuis 			return (0);
368d3c1e14bSEdwin Groothuis 		}
369d3c1e14bSEdwin Groothuis 		for (i = 0; i < hdr.elf.e_phnum; i++) {
370d3c1e14bSEdwin Groothuis 			if (read(fd, &phdr, hdr.elf.e_phentsize)
371d3c1e14bSEdwin Groothuis 			   != sizeof(phdr)) {
372d3c1e14bSEdwin Groothuis 				warnx("%s: can't read program header", fname);
373d3c1e14bSEdwin Groothuis 				return (0);
374d3c1e14bSEdwin Groothuis 			}
375d3c1e14bSEdwin Groothuis 			if (phdr.p_type == PT_DYNAMIC) {
376d3c1e14bSEdwin Groothuis 				dynamic = 1;
3772b5d88fdSKonstantin Belousov 				dynphdr = phdr;
378d3c1e14bSEdwin Groothuis 				break;
379d3c1e14bSEdwin Groothuis 			}
380d3c1e14bSEdwin Groothuis 		}
381d3c1e14bSEdwin Groothuis 
382d3c1e14bSEdwin Groothuis 		if (!dynamic) {
383d3c1e14bSEdwin Groothuis 			warnx("%s: not a dynamic ELF executable", fname);
384d3c1e14bSEdwin Groothuis 			return (0);
385d3c1e14bSEdwin Groothuis 		}
3862b5d88fdSKonstantin Belousov 
387d3c1e14bSEdwin Groothuis 		if (hdr.elf.e_type == ET_DYN) {
3882b5d88fdSKonstantin Belousov 			if (lseek(fd, dynphdr.p_offset, SEEK_SET) == -1) {
3892b5d88fdSKonstantin Belousov 				warnx("%s: dynamic segment out of range",
3902b5d88fdSKonstantin Belousov 				    fname);
3912b5d88fdSKonstantin Belousov 				return (0);
3922b5d88fdSKonstantin Belousov 			}
3932b5d88fdSKonstantin Belousov 			dyndata = malloc(dynphdr.p_filesz);
3942b5d88fdSKonstantin Belousov 			if (dyndata == NULL) {
3952b5d88fdSKonstantin Belousov 				warn("malloc");
3962b5d88fdSKonstantin Belousov 				return (0);
3972b5d88fdSKonstantin Belousov 			}
3982b5d88fdSKonstantin Belousov 			if (read(fd, dyndata, dynphdr.p_filesz) !=
3992b5d88fdSKonstantin Belousov 			    (ssize_t)dynphdr.p_filesz) {
4002b5d88fdSKonstantin Belousov 				free(dyndata);
4012b5d88fdSKonstantin Belousov 				warnx("%s: can't read dynamic segment", fname);
4022b5d88fdSKonstantin Belousov 				return (0);
4032b5d88fdSKonstantin Belousov 			}
4042b5d88fdSKonstantin Belousov 			for (dynp = dyndata; dynp->d_tag != DT_NULL; dynp++) {
4052b5d88fdSKonstantin Belousov 				if (dynp->d_tag != DT_FLAGS_1)
4062b5d88fdSKonstantin Belousov 					continue;
4072b5d88fdSKonstantin Belousov 				df1pie = (dynp->d_un.d_val & DF_1_PIE) != 0;
4082b5d88fdSKonstantin Belousov 				break;
4092b5d88fdSKonstantin Belousov 			}
4102b5d88fdSKonstantin Belousov 			free(dyndata);
4112b5d88fdSKonstantin Belousov 
412a41dab8fSJung-uk Kim 			switch (hdr.elf.e_ident[EI_OSABI]) {
413a41dab8fSJung-uk Kim 			case ELFOSABI_FREEBSD:
4142b5d88fdSKonstantin Belousov 				if (!df1pie)
415d3c1e14bSEdwin Groothuis 					*is_shlib = 1;
416d3c1e14bSEdwin Groothuis 				return (1);
417a41dab8fSJung-uk Kim #ifdef __ARM_EABI__
418a41dab8fSJung-uk Kim 			case ELFOSABI_NONE:
419a41dab8fSJung-uk Kim 				if (hdr.elf.e_machine != EM_ARM)
420a41dab8fSJung-uk Kim 					break;
421a41dab8fSJung-uk Kim 				if (EF_ARM_EABI_VERSION(hdr.elf.e_flags) <
422a41dab8fSJung-uk Kim 				    EF_ARM_EABI_FREEBSD_MIN)
423a41dab8fSJung-uk Kim 					break;
424a41dab8fSJung-uk Kim 				*is_shlib = 1;
425a41dab8fSJung-uk Kim 				return (1);
426a41dab8fSJung-uk Kim #endif
427d3c1e14bSEdwin Groothuis 			}
428d3c1e14bSEdwin Groothuis 			warnx("%s: not a FreeBSD ELF shared object", fname);
429d3c1e14bSEdwin Groothuis 			return (0);
430d3c1e14bSEdwin Groothuis 		}
431d3c1e14bSEdwin Groothuis 
432d3c1e14bSEdwin Groothuis 		return (1);
433d3c1e14bSEdwin Groothuis 	}
434d3c1e14bSEdwin Groothuis 
435d3c1e14bSEdwin Groothuis 	warnx("%s: not a dynamic executable", fname);
436d3c1e14bSEdwin Groothuis 	return (0);
437d3c1e14bSEdwin Groothuis }
438