xref: /freebsd/usr.bin/ldd/ldd.c (revision 9d4104b214963bb3371ada05cae8006940121634)
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 
36*9d4104b2SJohn Baldwin #include <sys/param.h>
37b9ae52e3SPaul Richards #include <sys/wait.h>
38a53809fdSMark Murray 
395e6220d9SDavid E. O'Brien #include <machine/elf.h>
40a53809fdSMark Murray 
41a2cfdda8SMike Barcroft #include <arpa/inet.h>
42a53809fdSMark Murray 
43c6de4ce7SMaxim Sobolev #include <dlfcn.h>
44699e1b82SRich Murphey #include <err.h>
45fffd993dSEdwin Groothuis #include <errno.h>
46699e1b82SRich Murphey #include <fcntl.h>
47*9d4104b2SJohn Baldwin #include <gelf.h>
48*9d4104b2SJohn Baldwin #include <libelf.h>
49*9d4104b2SJohn Baldwin #include <stdbool.h>
50699e1b82SRich Murphey #include <stdio.h>
51699e1b82SRich Murphey #include <stdlib.h>
52e68ed793SJohn Baldwin #include <string.h>
53699e1b82SRich Murphey #include <unistd.h>
54b9ae52e3SPaul Richards 
558bd833ffSEdwin Groothuis /*
56bff71350SEdwin Groothuis  * 32-bit ELF data structures can only be used if the system header[s] declare
57bff71350SEdwin Groothuis  * them.  There is no official macro for determining whether they are declared,
58bff71350SEdwin Groothuis  * so check for the existence of one of the 32-macros defined in elf(5).
598bd833ffSEdwin Groothuis  */
60bff71350SEdwin Groothuis #ifdef ELF32_R_TYPE
618bd833ffSEdwin Groothuis #define	ELF32_SUPPORTED
628bd833ffSEdwin Groothuis #endif
638bd833ffSEdwin Groothuis 
64a94a4b74SMark Johnston #define	LDD_SETENV(name, value, overwrite) do {		\
65a94a4b74SMark Johnston 	setenv("LD_" name, value, overwrite);		\
66a94a4b74SMark Johnston 	setenv("LD_32_" name, value, overwrite);	\
67a94a4b74SMark Johnston } while (0)
68a94a4b74SMark Johnston 
69a94a4b74SMark Johnston #define	LDD_UNSETENV(name) do {		\
70a94a4b74SMark Johnston 	unsetenv("LD_" name);		\
71a94a4b74SMark Johnston 	unsetenv("LD_32_" name);	\
72a94a4b74SMark Johnston } while (0)
73a94a4b74SMark Johnston 
74d3c1e14bSEdwin Groothuis static int	is_executable(const char *fname, int fd, int *is_shlib,
75d3c1e14bSEdwin Groothuis 		    int *type);
76d3c1e14bSEdwin Groothuis static void	usage(void);
77a0d476a9SEdwin Groothuis 
78d3c1e14bSEdwin Groothuis #define	TYPE_UNKNOWN	0
79c8eee7c0SEd Maste #define	TYPE_ELF	1	/* Architecture default */
808bd833ffSEdwin Groothuis #if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED)
81c8eee7c0SEd Maste #define	TYPE_ELF32	2	/* Explicit 32 bits on architectures >32 bits */
82d3c1e14bSEdwin Groothuis 
83e68ed793SJohn Baldwin #define	_PATH_LDD32	"/usr/bin/ldd32"
84d3c1e14bSEdwin Groothuis 
85e68ed793SJohn Baldwin static int
86e68ed793SJohn Baldwin execldd32(char *file, char *fmt1, char *fmt2, int aflag, int vflag)
87e68ed793SJohn Baldwin {
884b426307SDon Lewis 	char *argv[9];
89e68ed793SJohn Baldwin 	int i, rval, status;
90e68ed793SJohn Baldwin 
91a94a4b74SMark Johnston 	LDD_UNSETENV("TRACE_LOADED_OBJECTS");
92e68ed793SJohn Baldwin 	rval = 0;
93e68ed793SJohn Baldwin 	i = 0;
94e68ed793SJohn Baldwin 	argv[i++] = strdup(_PATH_LDD32);
95e68ed793SJohn Baldwin 	if (aflag)
96e68ed793SJohn Baldwin 		argv[i++] = strdup("-a");
97e68ed793SJohn Baldwin 	if (vflag)
98e68ed793SJohn Baldwin 		argv[i++] = strdup("-v");
9952122f31SJohn Baldwin 	if (fmt1 != NULL) {
100e68ed793SJohn Baldwin 		argv[i++] = strdup("-f");
101e68ed793SJohn Baldwin 		argv[i++] = strdup(fmt1);
102e68ed793SJohn Baldwin 	}
10352122f31SJohn Baldwin 	if (fmt2 != NULL) {
104e68ed793SJohn Baldwin 		argv[i++] = strdup("-f");
105e68ed793SJohn Baldwin 		argv[i++] = strdup(fmt2);
106e68ed793SJohn Baldwin 	}
107e68ed793SJohn Baldwin 	argv[i++] = strdup(file);
108e68ed793SJohn Baldwin 	argv[i++] = NULL;
109e68ed793SJohn Baldwin 
110e68ed793SJohn Baldwin 	switch (fork()) {
111e68ed793SJohn Baldwin 	case -1:
112e68ed793SJohn Baldwin 		err(1, "fork");
113e68ed793SJohn Baldwin 		break;
114e68ed793SJohn Baldwin 	case 0:
115e68ed793SJohn Baldwin 		execv(_PATH_LDD32, argv);
116e68ed793SJohn Baldwin 		warn("%s", _PATH_LDD32);
11752122f31SJohn Baldwin 		_exit(127);
118e68ed793SJohn Baldwin 		break;
119e68ed793SJohn Baldwin 	default:
12052122f31SJohn Baldwin 		if (wait(&status) < 0)
121e68ed793SJohn Baldwin 			rval = 1;
12252122f31SJohn Baldwin 		else if (WIFSIGNALED(status))
123e68ed793SJohn Baldwin 			rval = 1;
12452122f31SJohn Baldwin 		else if (WIFEXITED(status) && WEXITSTATUS(status) != 0)
125e68ed793SJohn Baldwin 			rval = 1;
126e68ed793SJohn Baldwin 		break;
127e68ed793SJohn Baldwin 	}
128e68ed793SJohn Baldwin 	while (i--)
129e68ed793SJohn Baldwin 		free(argv[i]);
130a94a4b74SMark Johnston 	LDD_SETENV("TRACE_LOADED_OBJECTS", "yes", 1);
131e68ed793SJohn Baldwin 	return (rval);
132e68ed793SJohn Baldwin }
133fffd993dSEdwin Groothuis #endif
134b9ae52e3SPaul Richards 
135b9ae52e3SPaul Richards int
136a53809fdSMark Murray main(int argc, char *argv[])
137b9ae52e3SPaul Richards {
138a0d476a9SEdwin Groothuis 	char *fmt1, *fmt2;
139a0d476a9SEdwin Groothuis 	int rval, c, aflag, vflag;
140b9ae52e3SPaul Richards 
14120249943SDavid E. O'Brien 	aflag = vflag = 0;
142a0d476a9SEdwin Groothuis 	fmt1 = fmt2 = NULL;
14320249943SDavid E. O'Brien 
144a0d476a9SEdwin Groothuis 	while ((c = getopt(argc, argv, "af:v")) != -1) {
145b9ae52e3SPaul Richards 		switch (c) {
14620249943SDavid E. O'Brien 		case 'a':
14720249943SDavid E. O'Brien 			aflag++;
14820249943SDavid E. O'Brien 			break;
149d138df61SPeter Wemm 		case 'f':
150a0d476a9SEdwin Groothuis 			if (fmt1 != NULL) {
151a0d476a9SEdwin Groothuis 				if (fmt2 != NULL)
1523e762626SPhilippe Charnier 					errx(1, "too many formats");
153d138df61SPeter Wemm 				fmt2 = optarg;
154d138df61SPeter Wemm 			} else
155d138df61SPeter Wemm 				fmt1 = optarg;
156d138df61SPeter Wemm 			break;
157a0d476a9SEdwin Groothuis 		case 'v':
158a0d476a9SEdwin Groothuis 			vflag++;
159a0d476a9SEdwin Groothuis 			break;
160b9ae52e3SPaul Richards 		default:
161b9ae52e3SPaul Richards 			usage();
162699e1b82SRich Murphey 			/* NOTREACHED */
163b9ae52e3SPaul Richards 		}
164b9ae52e3SPaul Richards 	}
165b9ae52e3SPaul Richards 	argc -= optind;
166b9ae52e3SPaul Richards 	argv += optind;
167b9ae52e3SPaul Richards 
168a0d476a9SEdwin Groothuis 	if (vflag && fmt1 != NULL)
1699731d137SPeter Wemm 		errx(1, "-v may not be used with -f");
1709731d137SPeter Wemm 
171b9ae52e3SPaul Richards 	if (argc <= 0) {
172b9ae52e3SPaul Richards 		usage();
173699e1b82SRich Murphey 		/* NOTREACHED */
174b9ae52e3SPaul Richards 	}
175b9ae52e3SPaul Richards 
176699e1b82SRich Murphey 	rval = 0;
177e2daa140SJohn Polstra 	for (; argc > 0; argc--, argv++) {
178d3c1e14bSEdwin Groothuis 		int fd, status, is_shlib, rv, type;
179d3c1e14bSEdwin Groothuis 
180b9ae52e3SPaul Richards 		if ((fd = open(*argv, O_RDONLY, 0)) < 0) {
181699e1b82SRich Murphey 			warn("%s", *argv);
182b9ae52e3SPaul Richards 			rval |= 1;
183b9ae52e3SPaul Richards 			continue;
184b9ae52e3SPaul Richards 		}
185d3c1e14bSEdwin Groothuis 		rv = is_executable(*argv, fd, &is_shlib, &type);
186a0d476a9SEdwin Groothuis 		close(fd);
187d3c1e14bSEdwin Groothuis 		if (rv == 0) {
188c474c6d3SDoug Rabson 			rval |= 1;
189c474c6d3SDoug Rabson 			continue;
190c474c6d3SDoug Rabson 		}
191c474c6d3SDoug Rabson 
192fffd993dSEdwin Groothuis 		switch (type) {
193fffd993dSEdwin Groothuis 		case TYPE_ELF:
194fffd993dSEdwin Groothuis 			break;
1958bd833ffSEdwin Groothuis #if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED)
196fffd993dSEdwin Groothuis 		case TYPE_ELF32:
197e68ed793SJohn Baldwin 			rval |= execldd32(*argv, fmt1, fmt2, aflag, vflag);
198e68ed793SJohn Baldwin 			continue;
199fffd993dSEdwin Groothuis #endif
200fffd993dSEdwin Groothuis 		case TYPE_UNKNOWN:
201fffd993dSEdwin Groothuis 		default:
202fffd993dSEdwin Groothuis 			/*
203fffd993dSEdwin Groothuis 			 * This shouldn't happen unless is_executable()
204fffd993dSEdwin Groothuis 			 * is broken.
205fffd993dSEdwin Groothuis 			 */
206fffd993dSEdwin Groothuis 			errx(EDOOFUS, "unknown executable type");
207fffd993dSEdwin Groothuis 		}
208fffd993dSEdwin Groothuis 
209d3c1e14bSEdwin Groothuis 		/* ld.so magic */
210a94a4b74SMark Johnston 		LDD_SETENV("TRACE_LOADED_OBJECTS", "yes", 1);
211d3c1e14bSEdwin Groothuis 		if (fmt1 != NULL)
212a94a4b74SMark Johnston 			LDD_SETENV("TRACE_LOADED_OBJECTS_FMT1", fmt1, 1);
213d3c1e14bSEdwin Groothuis 		if (fmt2 != NULL)
214a94a4b74SMark Johnston 			LDD_SETENV("TRACE_LOADED_OBJECTS_FMT2", fmt2, 1);
215a0d476a9SEdwin Groothuis 
216a94a4b74SMark Johnston 		LDD_SETENV("TRACE_LOADED_OBJECTS_PROGNAME", *argv, 1);
217a0d476a9SEdwin Groothuis 		if (aflag)
218a94a4b74SMark Johnston 			LDD_SETENV("TRACE_LOADED_OBJECTS_ALL", "1", 1);
21920249943SDavid E. O'Brien 		else if (fmt1 == NULL && fmt2 == NULL)
220d138df61SPeter Wemm 			/* Default formats */
221b9ae52e3SPaul Richards 			printf("%s:\n", *argv);
22209e3d49dSJordan K. Hubbard 		fflush(stdout);
223b9ae52e3SPaul Richards 
224b9ae52e3SPaul Richards 		switch (fork()) {
225b9ae52e3SPaul Richards 		case -1:
226699e1b82SRich Murphey 			err(1, "fork");
227b9ae52e3SPaul Richards 			break;
228b9ae52e3SPaul Richards 		default:
22952122f31SJohn Baldwin 			if (wait(&status) < 0) {
230699e1b82SRich Murphey 				warn("wait");
231699e1b82SRich Murphey 				rval |= 1;
232699e1b82SRich Murphey 			} else if (WIFSIGNALED(status)) {
233a0d476a9SEdwin Groothuis 				fprintf(stderr, "%s: signal %d\n", *argv,
234a0d476a9SEdwin Groothuis 				    WTERMSIG(status));
235b9ae52e3SPaul Richards 				rval |= 1;
23652122f31SJohn Baldwin 			} else if (WIFEXITED(status) &&
23752122f31SJohn Baldwin 			    WEXITSTATUS(status) != 0) {
238a0d476a9SEdwin Groothuis 				fprintf(stderr, "%s: exit status %d\n", *argv,
239a0d476a9SEdwin Groothuis 				    WEXITSTATUS(status));
240b9ae52e3SPaul Richards 				rval |= 1;
241b9ae52e3SPaul Richards 			}
242b9ae52e3SPaul Richards 			break;
243b9ae52e3SPaul Richards 		case 0:
244d1cf9ea2SMaxim Sobolev 			if (is_shlib == 0) {
245fc41545eSMaxim Sobolev 				execl(*argv, *argv, (char *)NULL);
2463e762626SPhilippe Charnier 				warn("%s", *argv);
247d1cf9ea2SMaxim Sobolev 			} else {
248d1cf9ea2SMaxim Sobolev 				dlopen(*argv, RTLD_TRACE);
249d1cf9ea2SMaxim Sobolev 				warnx("%s: %s", *argv, dlerror());
250c6de4ce7SMaxim Sobolev 			}
251b9ae52e3SPaul Richards 			_exit(1);
252b9ae52e3SPaul Richards 		}
253b9ae52e3SPaul Richards 	}
254b9ae52e3SPaul Richards 
255b9ae52e3SPaul Richards 	return rval;
256b9ae52e3SPaul Richards }
257d3c1e14bSEdwin Groothuis 
258d3c1e14bSEdwin Groothuis static void
259d3c1e14bSEdwin Groothuis usage(void)
260d3c1e14bSEdwin Groothuis {
261d3c1e14bSEdwin Groothuis 
262d3c1e14bSEdwin Groothuis 	fprintf(stderr, "usage: ldd [-a] [-v] [-f format] program ...\n");
263d3c1e14bSEdwin Groothuis 	exit(1);
264d3c1e14bSEdwin Groothuis }
265d3c1e14bSEdwin Groothuis 
266*9d4104b2SJohn Baldwin static bool
267*9d4104b2SJohn Baldwin has_freebsd_abi_tag(const char *fname, Elf *elf, GElf_Ehdr *ehdr, off_t offset,
268*9d4104b2SJohn Baldwin     size_t len)
269*9d4104b2SJohn Baldwin {
270*9d4104b2SJohn Baldwin 	Elf_Data dst, src;
271*9d4104b2SJohn Baldwin 	const Elf_Note *note;
272*9d4104b2SJohn Baldwin 	char *buf;
273*9d4104b2SJohn Baldwin 	const char *name;
274*9d4104b2SJohn Baldwin 	void *copy;
275*9d4104b2SJohn Baldwin 	size_t namesz, descsz;
276*9d4104b2SJohn Baldwin 	bool has_abi_tag;
277*9d4104b2SJohn Baldwin 
278*9d4104b2SJohn Baldwin 	buf = elf_rawfile(elf, NULL);
279*9d4104b2SJohn Baldwin 	if (buf == NULL) {
280*9d4104b2SJohn Baldwin 		warnx("%s: %s", fname, elf_errmsg(0));
281*9d4104b2SJohn Baldwin 		return (false);
282*9d4104b2SJohn Baldwin 	}
283*9d4104b2SJohn Baldwin 
284*9d4104b2SJohn Baldwin 	memset(&src, 0, sizeof(src));
285*9d4104b2SJohn Baldwin 	src.d_buf = buf + offset;
286*9d4104b2SJohn Baldwin 	src.d_size = len;
287*9d4104b2SJohn Baldwin 	src.d_type = ELF_T_NOTE;
288*9d4104b2SJohn Baldwin 	src.d_version = EV_CURRENT;
289*9d4104b2SJohn Baldwin 
290*9d4104b2SJohn Baldwin 	memset(&dst, 0, sizeof(dst));
291*9d4104b2SJohn Baldwin 	dst.d_buf = copy = malloc(len);
292*9d4104b2SJohn Baldwin 	dst.d_size = len;
293*9d4104b2SJohn Baldwin 	dst.d_type = ELF_T_NOTE;
294*9d4104b2SJohn Baldwin 	dst.d_version = EV_CURRENT;
295*9d4104b2SJohn Baldwin 
296*9d4104b2SJohn Baldwin 	if (gelf_xlatetom(elf, &dst, &src, ehdr->e_ident[EI_DATA]) == NULL) {
297*9d4104b2SJohn Baldwin 		warnx("%s: failed to parse notes: %s", fname, elf_errmsg(0));
298*9d4104b2SJohn Baldwin 		free(copy);
299*9d4104b2SJohn Baldwin 		return (false);
300*9d4104b2SJohn Baldwin 	}
301*9d4104b2SJohn Baldwin 
302*9d4104b2SJohn Baldwin 	buf = copy;
303*9d4104b2SJohn Baldwin 	has_abi_tag = false;
304*9d4104b2SJohn Baldwin 	for (;;) {
305*9d4104b2SJohn Baldwin 		if (len < sizeof(*note))
306*9d4104b2SJohn Baldwin 			break;
307*9d4104b2SJohn Baldwin 
308*9d4104b2SJohn Baldwin 		note = (const void *)buf;
309*9d4104b2SJohn Baldwin 		buf += sizeof(*note);
310*9d4104b2SJohn Baldwin 		len -= sizeof(*note);
311*9d4104b2SJohn Baldwin 
312*9d4104b2SJohn Baldwin 		namesz = roundup2(note->n_namesz, sizeof(uint32_t));
313*9d4104b2SJohn Baldwin 		descsz = roundup2(note->n_descsz, sizeof(uint32_t));
314*9d4104b2SJohn Baldwin 		if (len < namesz + descsz)
315*9d4104b2SJohn Baldwin 			break;
316*9d4104b2SJohn Baldwin 
317*9d4104b2SJohn Baldwin 		name = buf;
318*9d4104b2SJohn Baldwin 		if (note->n_namesz == sizeof(ELF_NOTE_FREEBSD) &&
319*9d4104b2SJohn Baldwin 		    strncmp(name, ELF_NOTE_FREEBSD, note->n_namesz) == 0 &&
320*9d4104b2SJohn Baldwin 		    note->n_type == NT_FREEBSD_ABI_TAG &&
321*9d4104b2SJohn Baldwin 		    note->n_descsz == sizeof(uint32_t)) {
322*9d4104b2SJohn Baldwin 			has_abi_tag = true;
323*9d4104b2SJohn Baldwin 			break;
324*9d4104b2SJohn Baldwin 		}
325*9d4104b2SJohn Baldwin 
326*9d4104b2SJohn Baldwin 		buf += namesz + descsz;
327*9d4104b2SJohn Baldwin 		len -= namesz + descsz;
328*9d4104b2SJohn Baldwin 	}
329*9d4104b2SJohn Baldwin 
330*9d4104b2SJohn Baldwin 	free(copy);
331*9d4104b2SJohn Baldwin 	return (has_abi_tag);
332*9d4104b2SJohn Baldwin }
333*9d4104b2SJohn Baldwin 
334*9d4104b2SJohn Baldwin static bool
335*9d4104b2SJohn Baldwin is_pie(const char *fname, Elf *elf, GElf_Ehdr *ehdr, off_t offset, size_t len)
336*9d4104b2SJohn Baldwin {
337*9d4104b2SJohn Baldwin 	Elf_Data dst, src;
338*9d4104b2SJohn Baldwin 	char *buf;
339*9d4104b2SJohn Baldwin 	void *copy;
340*9d4104b2SJohn Baldwin 	const GElf_Dyn *dyn;
341*9d4104b2SJohn Baldwin 	size_t dynsize;
342*9d4104b2SJohn Baldwin 	u_int count, i;
343*9d4104b2SJohn Baldwin 	bool pie;
344*9d4104b2SJohn Baldwin 
345*9d4104b2SJohn Baldwin 	buf = elf_rawfile(elf, NULL);
346*9d4104b2SJohn Baldwin 	if (buf == NULL) {
347*9d4104b2SJohn Baldwin 		warnx("%s: %s", fname, elf_errmsg(0));
348*9d4104b2SJohn Baldwin 		return (false);
349*9d4104b2SJohn Baldwin 	}
350*9d4104b2SJohn Baldwin 
351*9d4104b2SJohn Baldwin 	dynsize = gelf_fsize(elf, ELF_T_DYN, 1, EV_CURRENT);
352*9d4104b2SJohn Baldwin 	if (dynsize == 0) {
353*9d4104b2SJohn Baldwin 		warnx("%s: %s", fname, elf_errmsg(0));
354*9d4104b2SJohn Baldwin 		return (false);
355*9d4104b2SJohn Baldwin 	}
356*9d4104b2SJohn Baldwin 	count = len / dynsize;
357*9d4104b2SJohn Baldwin 
358*9d4104b2SJohn Baldwin 	memset(&src, 0, sizeof(src));
359*9d4104b2SJohn Baldwin 	src.d_buf = buf + offset;
360*9d4104b2SJohn Baldwin 	src.d_size = len;
361*9d4104b2SJohn Baldwin 	src.d_type = ELF_T_DYN;
362*9d4104b2SJohn Baldwin 	src.d_version = EV_CURRENT;
363*9d4104b2SJohn Baldwin 
364*9d4104b2SJohn Baldwin 	memset(&dst, 0, sizeof(dst));
365*9d4104b2SJohn Baldwin 	dst.d_buf = copy = malloc(count * sizeof(*dyn));
366*9d4104b2SJohn Baldwin 	dst.d_size = count * sizeof(*dyn);
367*9d4104b2SJohn Baldwin 	dst.d_type = ELF_T_DYN;
368*9d4104b2SJohn Baldwin 	dst.d_version = EV_CURRENT;
369*9d4104b2SJohn Baldwin 
370*9d4104b2SJohn Baldwin 	if (gelf_xlatetom(elf, &dst, &src, ehdr->e_ident[EI_DATA]) == NULL) {
371*9d4104b2SJohn Baldwin 		warnx("%s: failed to parse .dynamic: %s", fname, elf_errmsg(0));
372*9d4104b2SJohn Baldwin 		free(copy);
373*9d4104b2SJohn Baldwin 		return (false);
374*9d4104b2SJohn Baldwin 	}
375*9d4104b2SJohn Baldwin 
376*9d4104b2SJohn Baldwin 	dyn = copy;
377*9d4104b2SJohn Baldwin 	pie = false;
378*9d4104b2SJohn Baldwin 	for (i = 0; i < count; i++) {
379*9d4104b2SJohn Baldwin 		if (dyn[i].d_tag != DT_FLAGS_1)
380*9d4104b2SJohn Baldwin 			continue;
381*9d4104b2SJohn Baldwin 
382*9d4104b2SJohn Baldwin 		pie = (dyn[i].d_un.d_val & DF_1_PIE) != 0;
383*9d4104b2SJohn Baldwin 		break;
384*9d4104b2SJohn Baldwin 	}
385*9d4104b2SJohn Baldwin 
386*9d4104b2SJohn Baldwin 	free(copy);
387*9d4104b2SJohn Baldwin 	return (pie);
388*9d4104b2SJohn Baldwin }
389*9d4104b2SJohn Baldwin 
390d3c1e14bSEdwin Groothuis static int
391d3c1e14bSEdwin Groothuis is_executable(const char *fname, int fd, int *is_shlib, int *type)
392d3c1e14bSEdwin Groothuis {
393*9d4104b2SJohn Baldwin 	Elf *elf;
394*9d4104b2SJohn Baldwin 	GElf_Ehdr ehdr;
395*9d4104b2SJohn Baldwin 	GElf_Phdr phdr;
396*9d4104b2SJohn Baldwin 	bool dynamic, freebsd, pie;
397*9d4104b2SJohn Baldwin 	int i;
398d3c1e14bSEdwin Groothuis 
399d3c1e14bSEdwin Groothuis 	*is_shlib = 0;
400d3c1e14bSEdwin Groothuis 	*type = TYPE_UNKNOWN;
401*9d4104b2SJohn Baldwin 	dynamic = false;
402*9d4104b2SJohn Baldwin 	freebsd = false;
403*9d4104b2SJohn Baldwin 	pie = false;
404d3c1e14bSEdwin Groothuis 
405*9d4104b2SJohn Baldwin 	if (elf_version(EV_CURRENT) == EV_NONE) {
406*9d4104b2SJohn Baldwin 		warnx("unsupported libelf");
407d3c1e14bSEdwin Groothuis 		return (0);
408d3c1e14bSEdwin Groothuis 	}
409*9d4104b2SJohn Baldwin 	elf = elf_begin(fd, ELF_C_READ, NULL);
410*9d4104b2SJohn Baldwin 	if (elf == NULL) {
411*9d4104b2SJohn Baldwin 		warnx("%s: %s", fname, elf_errmsg(0));
412fffd993dSEdwin Groothuis 		return (0);
413fffd993dSEdwin Groothuis 	}
414*9d4104b2SJohn Baldwin 	if (elf_kind(elf) != ELF_K_ELF) {
415*9d4104b2SJohn Baldwin 		elf_end(elf);
416fffd993dSEdwin Groothuis 		warnx("%s: not a dynamic ELF executable", fname);
417fffd993dSEdwin Groothuis 		return (0);
418fffd993dSEdwin Groothuis 	}
419*9d4104b2SJohn Baldwin 	if (gelf_getehdr(elf, &ehdr) == NULL) {
420*9d4104b2SJohn Baldwin 		warnx("%s: %s", fname, elf_errmsg(0));
421*9d4104b2SJohn Baldwin 		elf_end(elf);
422fffd993dSEdwin Groothuis 		return (0);
423fffd993dSEdwin Groothuis 	}
424fffd993dSEdwin Groothuis 
425d3c1e14bSEdwin Groothuis 	*type = TYPE_ELF;
426*9d4104b2SJohn Baldwin #if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED)
427*9d4104b2SJohn Baldwin 	if (gelf_getclass(elf) == ELFCLASS32) {
428*9d4104b2SJohn Baldwin 		*type = TYPE_ELF32;
429*9d4104b2SJohn Baldwin 	}
430*9d4104b2SJohn Baldwin #endif
431d3c1e14bSEdwin Groothuis 
432*9d4104b2SJohn Baldwin 	freebsd = ehdr.e_ident[EI_OSABI] == ELFOSABI_FREEBSD;
433*9d4104b2SJohn Baldwin 	for (i = 0; i < ehdr.e_phnum; i++) {
434*9d4104b2SJohn Baldwin 		if (gelf_getphdr(elf, i, &phdr) == NULL) {
435*9d4104b2SJohn Baldwin 			warnx("%s: %s", fname, elf_errmsg(0));
436*9d4104b2SJohn Baldwin 			elf_end(elf);
437d3c1e14bSEdwin Groothuis 			return (0);
438d3c1e14bSEdwin Groothuis 		}
439*9d4104b2SJohn Baldwin 		switch (phdr.p_type) {
440*9d4104b2SJohn Baldwin 		case PT_NOTE:
441*9d4104b2SJohn Baldwin 			if (ehdr.e_ident[EI_OSABI] == ELFOSABI_NONE && !freebsd)
442*9d4104b2SJohn Baldwin 				freebsd = has_freebsd_abi_tag(fname, elf, &ehdr,
443*9d4104b2SJohn Baldwin 				    phdr.p_offset, phdr.p_filesz);
444*9d4104b2SJohn Baldwin 			break;
445*9d4104b2SJohn Baldwin 		case PT_DYNAMIC:
446*9d4104b2SJohn Baldwin 			dynamic = true;
447*9d4104b2SJohn Baldwin 			if (ehdr.e_type == ET_DYN)
448*9d4104b2SJohn Baldwin 				pie = is_pie(fname, elf, &ehdr, phdr.p_offset,
449*9d4104b2SJohn Baldwin 				    phdr.p_filesz);
450d3c1e14bSEdwin Groothuis 			break;
451d3c1e14bSEdwin Groothuis 		}
452d3c1e14bSEdwin Groothuis 	}
453d3c1e14bSEdwin Groothuis 
454d3c1e14bSEdwin Groothuis 	if (!dynamic) {
455*9d4104b2SJohn Baldwin 		elf_end(elf);
456d3c1e14bSEdwin Groothuis 		warnx("%s: not a dynamic ELF executable", fname);
457d3c1e14bSEdwin Groothuis 		return (0);
458d3c1e14bSEdwin Groothuis 	}
4592b5d88fdSKonstantin Belousov 
460*9d4104b2SJohn Baldwin 	if (ehdr.e_type == ET_DYN && !pie) {
461*9d4104b2SJohn Baldwin 		*is_shlib = 1;
4622b5d88fdSKonstantin Belousov 
463*9d4104b2SJohn Baldwin 		if (!freebsd) {
464*9d4104b2SJohn Baldwin 			elf_end(elf);
465d3c1e14bSEdwin Groothuis 			warnx("%s: not a FreeBSD ELF shared object", fname);
466d3c1e14bSEdwin Groothuis 			return (0);
467d3c1e14bSEdwin Groothuis 		}
468d3c1e14bSEdwin Groothuis 	}
469d3c1e14bSEdwin Groothuis 
470*9d4104b2SJohn Baldwin 	elf_end(elf);
471*9d4104b2SJohn Baldwin 	return (1);
472d3c1e14bSEdwin Groothuis }
473