xref: /freebsd/usr.bin/ldd/ldd.c (revision 8bd833fff8e7658f77839cd1a3a8ecf48700e3f7)
1b9ae52e3SPaul Richards /*
2b9ae52e3SPaul Richards  * Copyright (c) 1993 Paul Kranenburg
3b9ae52e3SPaul Richards  * All rights reserved.
4b9ae52e3SPaul Richards  *
5b9ae52e3SPaul Richards  * Redistribution and use in source and binary forms, with or without
6b9ae52e3SPaul Richards  * modification, are permitted provided that the following conditions
7b9ae52e3SPaul Richards  * are met:
8b9ae52e3SPaul Richards  * 1. Redistributions of source code must retain the above copyright
9b9ae52e3SPaul Richards  *    notice, this list of conditions and the following disclaimer.
10b9ae52e3SPaul Richards  * 2. Redistributions in binary form must reproduce the above copyright
11b9ae52e3SPaul Richards  *    notice, this list of conditions and the following disclaimer in the
12b9ae52e3SPaul Richards  *    documentation and/or other materials provided with the distribution.
13b9ae52e3SPaul Richards  * 3. All advertising materials mentioning features or use of this software
14b9ae52e3SPaul Richards  *    must display the following acknowledgement:
15b9ae52e3SPaul Richards  *      This product includes software developed by Paul Kranenburg.
16b9ae52e3SPaul Richards  * 4. The name of the author may not be used to endorse or promote products
1709e3d49dSJordan K. Hubbard  *    derived from this software without specific prior written permission
18b9ae52e3SPaul Richards  *
19b9ae52e3SPaul Richards  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20b9ae52e3SPaul Richards  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21b9ae52e3SPaul Richards  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22b9ae52e3SPaul Richards  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23b9ae52e3SPaul Richards  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24b9ae52e3SPaul Richards  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25b9ae52e3SPaul Richards  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26b9ae52e3SPaul Richards  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27b9ae52e3SPaul Richards  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28b9ae52e3SPaul Richards  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29b9ae52e3SPaul Richards  */
30b9ae52e3SPaul Richards 
31a53809fdSMark Murray #include <sys/cdefs.h>
32a53809fdSMark Murray __FBSDID("$FreeBSD$");
333e762626SPhilippe Charnier 
34b9ae52e3SPaul Richards #include <sys/wait.h>
35a53809fdSMark Murray 
365e6220d9SDavid E. O'Brien #include <machine/elf.h>
37a53809fdSMark Murray 
38a2cfdda8SMike Barcroft #include <arpa/inet.h>
39a53809fdSMark Murray 
40b9ae52e3SPaul Richards #include <a.out.h>
41c6de4ce7SMaxim Sobolev #include <dlfcn.h>
42699e1b82SRich Murphey #include <err.h>
43fffd993dSEdwin Groothuis #include <errno.h>
44699e1b82SRich Murphey #include <fcntl.h>
45699e1b82SRich Murphey #include <stdio.h>
46699e1b82SRich Murphey #include <stdlib.h>
47699e1b82SRich Murphey #include <unistd.h>
48b9ae52e3SPaul Richards 
49a53809fdSMark Murray #include "extern.h"
509731d137SPeter Wemm 
518bd833ffSEdwin Groothuis /*
528bd833ffSEdwin Groothuis  * Elf32_xhdr structures can only be used if sys/elf32.h is included, so
538bd833ffSEdwin Groothuis  * check for the existence of one of the macros defined in sys/elf32.h.
548bd833ffSEdwin Groothuis  *
558bd833ffSEdwin Groothuis  * The presense of the ELF32_R_TYPE macro via machine/elf.h has been verified
568bd833ffSEdwin Groothuis  * on amd64 6.3, ia64 7.0 and sparc64 7.0.  The absence of the macro has been
578bd833ffSEdwin Groothuis  * verified on alpha 6.2.
588bd833ffSEdwin Groothuis  */
598bd833ffSEdwin Groothuis #if defined(ELF32_R_TYPE)
608bd833ffSEdwin Groothuis #define ELF32_SUPPORTED
618bd833ffSEdwin Groothuis #endif
628bd833ffSEdwin Groothuis 
63d3c1e14bSEdwin Groothuis static int	is_executable(const char *fname, int fd, int *is_shlib,
64d3c1e14bSEdwin Groothuis 		    int *type);
65d3c1e14bSEdwin Groothuis static void	usage(void);
66a0d476a9SEdwin Groothuis 
67d3c1e14bSEdwin Groothuis #define	TYPE_UNKNOWN	0
68d3c1e14bSEdwin Groothuis #define	TYPE_AOUT	1
69d3c1e14bSEdwin Groothuis #define	TYPE_ELF	2	/* Architecture default */
708bd833ffSEdwin Groothuis #if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED)
71fffd993dSEdwin Groothuis #define	TYPE_ELF32	3	/* Explicit 32 bits on architectures >32 bits */
72fffd993dSEdwin Groothuis #endif
73d3c1e14bSEdwin Groothuis 
74d3c1e14bSEdwin Groothuis #define	ENV_OBJECTS		0
75d3c1e14bSEdwin Groothuis #define	ENV_OBJECTS_FMT1	1
76d3c1e14bSEdwin Groothuis #define	ENV_OBJECTS_FMT2	2
77d3c1e14bSEdwin Groothuis #define	ENV_OBJECTS_PROGNAME	3
78d3c1e14bSEdwin Groothuis #define	ENV_OBJECTS_ALL		4
79d3c1e14bSEdwin Groothuis #define	ENV_LAST		5
80d3c1e14bSEdwin Groothuis 
81d3c1e14bSEdwin Groothuis const char	*envdef[ENV_LAST] = {
82d3c1e14bSEdwin Groothuis 	"LD_TRACE_LOADED_OBJECTS",
83d3c1e14bSEdwin Groothuis 	"LD_TRACE_LOADED_OBJECTS_FMT1",
84d3c1e14bSEdwin Groothuis 	"LD_TRACE_LOADED_OBJECTS_FMT2",
85d3c1e14bSEdwin Groothuis 	"LD_TRACE_LOADED_OBJECTS_PROGNAME",
86d3c1e14bSEdwin Groothuis 	"LD_TRACE_LOADED_OBJECTS_ALL",
87d3c1e14bSEdwin Groothuis };
888bd833ffSEdwin Groothuis #if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED)
89fffd993dSEdwin Groothuis const char	*env32[ENV_LAST] = {
90fffd993dSEdwin Groothuis 	"LD_32_TRACE_LOADED_OBJECTS",
91fffd993dSEdwin Groothuis 	"LD_32_TRACE_LOADED_OBJECTS_FMT1",
92fffd993dSEdwin Groothuis 	"LD_32_TRACE_LOADED_OBJECTS_FMT2",
93fffd993dSEdwin Groothuis 	"LD_32_TRACE_LOADED_OBJECTS_PROGNAME",
94fffd993dSEdwin Groothuis 	"LD_32_TRACE_LOADED_OBJECTS_ALL",
95fffd993dSEdwin Groothuis };
96fffd993dSEdwin Groothuis #endif
97b9ae52e3SPaul Richards 
98b9ae52e3SPaul Richards int
99a53809fdSMark Murray main(int argc, char *argv[])
100b9ae52e3SPaul Richards {
101a0d476a9SEdwin Groothuis 	char *fmt1, *fmt2;
102a0d476a9SEdwin Groothuis 	int rval, c, aflag, vflag;
103b9ae52e3SPaul Richards 
10420249943SDavid E. O'Brien 	aflag = vflag = 0;
105a0d476a9SEdwin Groothuis 	fmt1 = fmt2 = NULL;
10620249943SDavid E. O'Brien 
107a0d476a9SEdwin Groothuis 	while ((c = getopt(argc, argv, "af:v")) != -1) {
108b9ae52e3SPaul Richards 		switch (c) {
10920249943SDavid E. O'Brien 		case 'a':
11020249943SDavid E. O'Brien 			aflag++;
11120249943SDavid E. O'Brien 			break;
112d138df61SPeter Wemm 		case 'f':
113a0d476a9SEdwin Groothuis 			if (fmt1 != NULL) {
114a0d476a9SEdwin Groothuis 				if (fmt2 != NULL)
1153e762626SPhilippe Charnier 					errx(1, "too many formats");
116d138df61SPeter Wemm 				fmt2 = optarg;
117d138df61SPeter Wemm 			} else
118d138df61SPeter Wemm 				fmt1 = optarg;
119d138df61SPeter Wemm 			break;
120a0d476a9SEdwin Groothuis 		case 'v':
121a0d476a9SEdwin Groothuis 			vflag++;
122a0d476a9SEdwin Groothuis 			break;
123b9ae52e3SPaul Richards 		default:
124b9ae52e3SPaul Richards 			usage();
125699e1b82SRich Murphey 			/* NOTREACHED */
126b9ae52e3SPaul Richards 		}
127b9ae52e3SPaul Richards 	}
128b9ae52e3SPaul Richards 	argc -= optind;
129b9ae52e3SPaul Richards 	argv += optind;
130b9ae52e3SPaul Richards 
131a0d476a9SEdwin Groothuis 	if (vflag && fmt1 != NULL)
1329731d137SPeter Wemm 		errx(1, "-v may not be used with -f");
1339731d137SPeter Wemm 
134b9ae52e3SPaul Richards 	if (argc <= 0) {
135b9ae52e3SPaul Richards 		usage();
136699e1b82SRich Murphey 		/* NOTREACHED */
137b9ae52e3SPaul Richards 	}
138b9ae52e3SPaul Richards 
13997db68b6SDoug Rabson #ifdef __i386__
1409731d137SPeter Wemm 	if (vflag) {
1419731d137SPeter Wemm 		for (c = 0; c < argc; c++)
1429731d137SPeter Wemm 			dump_file(argv[c]);
1439731d137SPeter Wemm 		exit(error_count == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
1449731d137SPeter Wemm 	}
14597db68b6SDoug Rabson #endif
1469731d137SPeter Wemm 
147699e1b82SRich Murphey 	rval = 0;
148e2daa140SJohn Polstra 	for (; argc > 0; argc--, argv++) {
149d3c1e14bSEdwin Groothuis 		int fd, status, is_shlib, rv, type;
150d3c1e14bSEdwin Groothuis 		const char **env;
151d3c1e14bSEdwin Groothuis 
152b9ae52e3SPaul Richards 		if ((fd = open(*argv, O_RDONLY, 0)) < 0) {
153699e1b82SRich Murphey 			warn("%s", *argv);
154b9ae52e3SPaul Richards 			rval |= 1;
155b9ae52e3SPaul Richards 			continue;
156b9ae52e3SPaul Richards 		}
157d3c1e14bSEdwin Groothuis 		rv = is_executable(*argv, fd, &is_shlib, &type);
158a0d476a9SEdwin Groothuis 		close(fd);
159d3c1e14bSEdwin Groothuis 		if (rv == 0) {
160c474c6d3SDoug Rabson 			rval |= 1;
161c474c6d3SDoug Rabson 			continue;
162c474c6d3SDoug Rabson 		}
163c474c6d3SDoug Rabson 
164fffd993dSEdwin Groothuis 		switch (type) {
165fffd993dSEdwin Groothuis 		case TYPE_ELF:
166fffd993dSEdwin Groothuis 		case TYPE_AOUT:
167fffd993dSEdwin Groothuis 			env = envdef;
168fffd993dSEdwin Groothuis 			break;
1698bd833ffSEdwin Groothuis #if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED)
170fffd993dSEdwin Groothuis 		case TYPE_ELF32:
171fffd993dSEdwin Groothuis 			env = env32;
172fffd993dSEdwin Groothuis 			break;
173fffd993dSEdwin Groothuis #endif
174fffd993dSEdwin Groothuis 		case TYPE_UNKNOWN:
175fffd993dSEdwin Groothuis 		default:
176fffd993dSEdwin Groothuis 			/*
177fffd993dSEdwin Groothuis 			 * This shouldn't happen unless is_executable()
178fffd993dSEdwin Groothuis 			 * is broken.
179fffd993dSEdwin Groothuis 			 */
180fffd993dSEdwin Groothuis 			errx(EDOOFUS, "unknown executable type");
181fffd993dSEdwin Groothuis 		}
182fffd993dSEdwin Groothuis 
183d3c1e14bSEdwin Groothuis 		/* ld.so magic */
184d3c1e14bSEdwin Groothuis 		setenv(env[ENV_OBJECTS], "yes", 1);
185d3c1e14bSEdwin Groothuis 		if (fmt1 != NULL)
186d3c1e14bSEdwin Groothuis 			setenv(env[ENV_OBJECTS_FMT1], fmt1, 1);
187d3c1e14bSEdwin Groothuis 		if (fmt2 != NULL)
188d3c1e14bSEdwin Groothuis 			setenv(env[ENV_OBJECTS_FMT2], fmt2, 1);
189a0d476a9SEdwin Groothuis 
190d3c1e14bSEdwin Groothuis 		setenv(env[ENV_OBJECTS_PROGNAME], *argv, 1);
191a0d476a9SEdwin Groothuis 		if (aflag)
192d3c1e14bSEdwin Groothuis 			setenv(env[ENV_OBJECTS_ALL], "1", 1);
19320249943SDavid E. O'Brien 		else if (fmt1 == NULL && fmt2 == NULL)
194d138df61SPeter Wemm 			/* Default formats */
195b9ae52e3SPaul Richards 			printf("%s:\n", *argv);
19609e3d49dSJordan K. Hubbard 		fflush(stdout);
197b9ae52e3SPaul Richards 
198b9ae52e3SPaul Richards 		switch (fork()) {
199b9ae52e3SPaul Richards 		case -1:
200699e1b82SRich Murphey 			err(1, "fork");
201b9ae52e3SPaul Richards 			break;
202b9ae52e3SPaul Richards 		default:
203699e1b82SRich Murphey 			if (wait(&status) <= 0) {
204699e1b82SRich Murphey 				warn("wait");
205699e1b82SRich Murphey 				rval |= 1;
206699e1b82SRich Murphey 			} else if (WIFSIGNALED(status)) {
207a0d476a9SEdwin Groothuis 				fprintf(stderr, "%s: signal %d\n", *argv,
208a0d476a9SEdwin Groothuis 				    WTERMSIG(status));
209b9ae52e3SPaul Richards 				rval |= 1;
210b9ae52e3SPaul Richards 			} else if (WIFEXITED(status) && WEXITSTATUS(status)) {
211a0d476a9SEdwin Groothuis 				fprintf(stderr, "%s: exit status %d\n", *argv,
212a0d476a9SEdwin Groothuis 				    WEXITSTATUS(status));
213b9ae52e3SPaul Richards 				rval |= 1;
214b9ae52e3SPaul Richards 			}
215b9ae52e3SPaul Richards 			break;
216b9ae52e3SPaul Richards 		case 0:
217d1cf9ea2SMaxim Sobolev 			if (is_shlib == 0) {
218fc41545eSMaxim Sobolev 				execl(*argv, *argv, (char *)NULL);
2193e762626SPhilippe Charnier 				warn("%s", *argv);
220d1cf9ea2SMaxim Sobolev 			} else {
221d1cf9ea2SMaxim Sobolev 				dlopen(*argv, RTLD_TRACE);
222d1cf9ea2SMaxim Sobolev 				warnx("%s: %s", *argv, dlerror());
223c6de4ce7SMaxim Sobolev 			}
224b9ae52e3SPaul Richards 			_exit(1);
225b9ae52e3SPaul Richards 		}
226b9ae52e3SPaul Richards 	}
227b9ae52e3SPaul Richards 
228b9ae52e3SPaul Richards 	return rval;
229b9ae52e3SPaul Richards }
230d3c1e14bSEdwin Groothuis 
231d3c1e14bSEdwin Groothuis static void
232d3c1e14bSEdwin Groothuis usage(void)
233d3c1e14bSEdwin Groothuis {
234d3c1e14bSEdwin Groothuis 
235d3c1e14bSEdwin Groothuis 	fprintf(stderr, "usage: ldd [-a] [-v] [-f format] program ...\n");
236d3c1e14bSEdwin Groothuis 	exit(1);
237d3c1e14bSEdwin Groothuis }
238d3c1e14bSEdwin Groothuis 
239d3c1e14bSEdwin Groothuis static int
240d3c1e14bSEdwin Groothuis is_executable(const char *fname, int fd, int *is_shlib, int *type)
241d3c1e14bSEdwin Groothuis {
242d3c1e14bSEdwin Groothuis 	union {
243d3c1e14bSEdwin Groothuis 		struct exec aout;
2448bd833ffSEdwin Groothuis #if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED)
245fffd993dSEdwin Groothuis 		Elf32_Ehdr elf32;
2468bd833ffSEdwin Groothuis #endif
247d3c1e14bSEdwin Groothuis 		Elf_Ehdr elf;
248d3c1e14bSEdwin Groothuis 	} hdr;
249d3c1e14bSEdwin Groothuis 	int n;
250d3c1e14bSEdwin Groothuis 
251d3c1e14bSEdwin Groothuis 	*is_shlib = 0;
252d3c1e14bSEdwin Groothuis 	*type = TYPE_UNKNOWN;
253d3c1e14bSEdwin Groothuis 
254d3c1e14bSEdwin Groothuis 	if ((n = read(fd, &hdr, sizeof(hdr))) == -1) {
255d3c1e14bSEdwin Groothuis 		warn("%s: can't read program header", fname);
256d3c1e14bSEdwin Groothuis 		return (0);
257d3c1e14bSEdwin Groothuis 	}
258d3c1e14bSEdwin Groothuis 
259d3c1e14bSEdwin Groothuis 	if ((size_t)n >= sizeof(hdr.aout) && !N_BADMAG(hdr.aout)) {
260d3c1e14bSEdwin Groothuis 		/* a.out file */
261d3c1e14bSEdwin Groothuis 		if ((N_GETFLAG(hdr.aout) & EX_DPMASK) != EX_DYNAMIC
262d3c1e14bSEdwin Groothuis #if 1 /* Compatibility */
263d3c1e14bSEdwin Groothuis 		    || hdr.aout.a_entry < __LDPGSZ
264d3c1e14bSEdwin Groothuis #endif
265d3c1e14bSEdwin Groothuis 			) {
266d3c1e14bSEdwin Groothuis 			warnx("%s: not a dynamic executable", fname);
267d3c1e14bSEdwin Groothuis 			return (0);
268d3c1e14bSEdwin Groothuis 		}
269d3c1e14bSEdwin Groothuis 		*type = TYPE_AOUT;
270d3c1e14bSEdwin Groothuis 		return (1);
271d3c1e14bSEdwin Groothuis 	}
272d3c1e14bSEdwin Groothuis 
2738bd833ffSEdwin Groothuis #if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED)
274fffd993dSEdwin Groothuis 	if ((size_t)n >= sizeof(hdr.elf32) && IS_ELF(hdr.elf32) &&
275fffd993dSEdwin Groothuis 	    hdr.elf32.e_ident[EI_CLASS] == ELFCLASS32) {
276fffd993dSEdwin Groothuis 		/* Handle 32 bit ELF objects */
277fffd993dSEdwin Groothuis 		Elf32_Phdr phdr;
278fffd993dSEdwin Groothuis 		int dynamic, i;
279fffd993dSEdwin Groothuis 
280fffd993dSEdwin Groothuis 		dynamic = 0;
281fffd993dSEdwin Groothuis 		*type = TYPE_ELF32;
282fffd993dSEdwin Groothuis 
283fffd993dSEdwin Groothuis 		if (lseek(fd, hdr.elf32.e_phoff, SEEK_SET) == -1) {
284fffd993dSEdwin Groothuis 			warnx("%s: header too short", fname);
285fffd993dSEdwin Groothuis 			return (0);
286fffd993dSEdwin Groothuis 		}
287fffd993dSEdwin Groothuis 		for (i = 0; i < hdr.elf32.e_phnum; i++) {
288fffd993dSEdwin Groothuis 			if (read(fd, &phdr, hdr.elf32.e_phentsize) !=
289fffd993dSEdwin Groothuis 			    sizeof(phdr)) {
290fffd993dSEdwin Groothuis 				warnx("%s: can't read program header", fname);
291fffd993dSEdwin Groothuis 				return (0);
292fffd993dSEdwin Groothuis 			}
293fffd993dSEdwin Groothuis 			if (phdr.p_type == PT_DYNAMIC) {
294fffd993dSEdwin Groothuis 				dynamic = 1;
295fffd993dSEdwin Groothuis 				break;
296fffd993dSEdwin Groothuis 			}
297fffd993dSEdwin Groothuis 		}
298fffd993dSEdwin Groothuis 
299fffd993dSEdwin Groothuis 		if (!dynamic) {
300fffd993dSEdwin Groothuis 			warnx("%s: not a dynamic ELF executable", fname);
301fffd993dSEdwin Groothuis 			return (0);
302fffd993dSEdwin Groothuis 		}
303fffd993dSEdwin Groothuis 		if (hdr.elf32.e_type == ET_DYN) {
304fffd993dSEdwin Groothuis 			if (hdr.elf32.e_ident[EI_OSABI] & ELFOSABI_FREEBSD) {
305fffd993dSEdwin Groothuis 				*is_shlib = 1;
306fffd993dSEdwin Groothuis 				return (1);
307fffd993dSEdwin Groothuis 			}
308fffd993dSEdwin Groothuis 			warnx("%s: not a FreeBSD ELF shared object", fname);
309fffd993dSEdwin Groothuis 			return (0);
310fffd993dSEdwin Groothuis 		}
311fffd993dSEdwin Groothuis 
312fffd993dSEdwin Groothuis 		return (1);
313fffd993dSEdwin Groothuis 	}
314fffd993dSEdwin Groothuis #endif
315fffd993dSEdwin Groothuis 
316d3c1e14bSEdwin Groothuis 	if ((size_t)n >= sizeof(hdr.elf) && IS_ELF(hdr.elf) &&
317d3c1e14bSEdwin Groothuis 	    hdr.elf.e_ident[EI_CLASS] == ELF_TARG_CLASS) {
318d3c1e14bSEdwin Groothuis 		/* Handle default ELF objects on this architecture */
319d3c1e14bSEdwin Groothuis 		Elf_Phdr phdr;
320d3c1e14bSEdwin Groothuis 		int dynamic, i;
321d3c1e14bSEdwin Groothuis 
322d3c1e14bSEdwin Groothuis 		dynamic = 0;
323d3c1e14bSEdwin Groothuis 		*type = TYPE_ELF;
324d3c1e14bSEdwin Groothuis 
325d3c1e14bSEdwin Groothuis 		if (lseek(fd, hdr.elf.e_phoff, SEEK_SET) == -1) {
326d3c1e14bSEdwin Groothuis 			warnx("%s: header too short", fname);
327d3c1e14bSEdwin Groothuis 			return (0);
328d3c1e14bSEdwin Groothuis 		}
329d3c1e14bSEdwin Groothuis 		for (i = 0; i < hdr.elf.e_phnum; i++) {
330d3c1e14bSEdwin Groothuis 			if (read(fd, &phdr, hdr.elf.e_phentsize)
331d3c1e14bSEdwin Groothuis 			   != sizeof(phdr)) {
332d3c1e14bSEdwin Groothuis 				warnx("%s: can't read program header", fname);
333d3c1e14bSEdwin Groothuis 				return (0);
334d3c1e14bSEdwin Groothuis 			}
335d3c1e14bSEdwin Groothuis 			if (phdr.p_type == PT_DYNAMIC) {
336d3c1e14bSEdwin Groothuis 				dynamic = 1;
337d3c1e14bSEdwin Groothuis 				break;
338d3c1e14bSEdwin Groothuis 			}
339d3c1e14bSEdwin Groothuis 		}
340d3c1e14bSEdwin Groothuis 
341d3c1e14bSEdwin Groothuis 		if (!dynamic) {
342d3c1e14bSEdwin Groothuis 			warnx("%s: not a dynamic ELF executable", fname);
343d3c1e14bSEdwin Groothuis 			return (0);
344d3c1e14bSEdwin Groothuis 		}
345d3c1e14bSEdwin Groothuis 		if (hdr.elf.e_type == ET_DYN) {
346d3c1e14bSEdwin Groothuis 			if (hdr.elf.e_ident[EI_OSABI] & ELFOSABI_FREEBSD) {
347d3c1e14bSEdwin Groothuis 				*is_shlib = 1;
348d3c1e14bSEdwin Groothuis 				return (1);
349d3c1e14bSEdwin Groothuis 			}
350d3c1e14bSEdwin Groothuis 			warnx("%s: not a FreeBSD ELF shared object", fname);
351d3c1e14bSEdwin Groothuis 			return (0);
352d3c1e14bSEdwin Groothuis 		}
353d3c1e14bSEdwin Groothuis 
354d3c1e14bSEdwin Groothuis 		return (1);
355d3c1e14bSEdwin Groothuis 	}
356d3c1e14bSEdwin Groothuis 
357d3c1e14bSEdwin Groothuis 	warnx("%s: not a dynamic executable", fname);
358d3c1e14bSEdwin Groothuis 	return (0);
359d3c1e14bSEdwin Groothuis }
360