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
339d4104b2SJohn Baldwin #include <sys/param.h>
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
40c6de4ce7SMaxim Sobolev #include <dlfcn.h>
41699e1b82SRich Murphey #include <err.h>
42fffd993dSEdwin Groothuis #include <errno.h>
43699e1b82SRich Murphey #include <fcntl.h>
449d4104b2SJohn Baldwin #include <gelf.h>
459d4104b2SJohn Baldwin #include <libelf.h>
462c7a6dadSKonstantin Belousov #include <rtld_paths.h>
479d4104b2SJohn Baldwin #include <stdbool.h>
48699e1b82SRich Murphey #include <stdio.h>
49699e1b82SRich Murphey #include <stdlib.h>
50e68ed793SJohn Baldwin #include <string.h>
51699e1b82SRich Murphey #include <unistd.h>
52b9ae52e3SPaul Richards
538bd833ffSEdwin Groothuis /*
54bff71350SEdwin Groothuis * 32-bit ELF data structures can only be used if the system header[s] declare
55bff71350SEdwin Groothuis * them. There is no official macro for determining whether they are declared,
56bff71350SEdwin Groothuis * so check for the existence of one of the 32-macros defined in elf(5).
578bd833ffSEdwin Groothuis */
58bff71350SEdwin Groothuis #ifdef ELF32_R_TYPE
598bd833ffSEdwin Groothuis #define ELF32_SUPPORTED
608bd833ffSEdwin Groothuis #endif
618bd833ffSEdwin Groothuis
62a94a4b74SMark Johnston #define LDD_SETENV(name, value, overwrite) do { \
63a94a4b74SMark Johnston setenv("LD_" name, value, overwrite); \
64a94a4b74SMark Johnston setenv("LD_32_" name, value, overwrite); \
65a94a4b74SMark Johnston } while (0)
66a94a4b74SMark Johnston
67a94a4b74SMark Johnston #define LDD_UNSETENV(name) do { \
68a94a4b74SMark Johnston unsetenv("LD_" name); \
69a94a4b74SMark Johnston unsetenv("LD_32_" name); \
70a94a4b74SMark Johnston } while (0)
71a94a4b74SMark Johnston
72d3c1e14bSEdwin Groothuis static int is_executable(const char *fname, int fd, int *is_shlib,
73d3c1e14bSEdwin Groothuis int *type);
74d3c1e14bSEdwin Groothuis static void usage(void);
75a0d476a9SEdwin Groothuis
76d3c1e14bSEdwin Groothuis #define TYPE_UNKNOWN 0
77c8eee7c0SEd Maste #define TYPE_ELF 1 /* Architecture default */
788bd833ffSEdwin Groothuis #if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED)
79c8eee7c0SEd Maste #define TYPE_ELF32 2 /* Explicit 32 bits on architectures >32 bits */
80d3c1e14bSEdwin Groothuis
81e68ed793SJohn Baldwin #define _PATH_LDD32 "/usr/bin/ldd32"
82d3c1e14bSEdwin Groothuis
83e68ed793SJohn Baldwin static int
execldd32(char * file,char * fmt1,char * fmt2,int aflag)8417fc43bcSKonstantin Belousov execldd32(char *file, char *fmt1, char *fmt2, int aflag)
85e68ed793SJohn Baldwin {
864b426307SDon Lewis char *argv[9];
87e68ed793SJohn Baldwin int i, rval, status;
88e68ed793SJohn Baldwin
89a94a4b74SMark Johnston LDD_UNSETENV("TRACE_LOADED_OBJECTS");
90e68ed793SJohn Baldwin rval = 0;
91e68ed793SJohn Baldwin i = 0;
92e68ed793SJohn Baldwin argv[i++] = strdup(_PATH_LDD32);
93e68ed793SJohn Baldwin if (aflag)
94e68ed793SJohn Baldwin argv[i++] = strdup("-a");
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
main(int argc,char * argv[])132a53809fdSMark Murray main(int argc, char *argv[])
133b9ae52e3SPaul Richards {
134a0d476a9SEdwin Groothuis char *fmt1, *fmt2;
1352c7a6dadSKonstantin Belousov const char *rtld;
136ca8c576dSKonstantin Belousov int aflag, c, fd, rval, status, is_shlib, rv, type;
137b9ae52e3SPaul Richards
13817fc43bcSKonstantin Belousov aflag = 0;
139a0d476a9SEdwin Groothuis fmt1 = fmt2 = NULL;
14020249943SDavid E. O'Brien
14117fc43bcSKonstantin Belousov while ((c = getopt(argc, argv, "af:")) != -1) {
142b9ae52e3SPaul Richards switch (c) {
14320249943SDavid E. O'Brien case 'a':
14420249943SDavid E. O'Brien aflag++;
14520249943SDavid E. O'Brien break;
146d138df61SPeter Wemm case 'f':
147a0d476a9SEdwin Groothuis if (fmt1 != NULL) {
148a0d476a9SEdwin Groothuis if (fmt2 != NULL)
1493e762626SPhilippe Charnier errx(1, "too many formats");
150d138df61SPeter Wemm fmt2 = optarg;
151d138df61SPeter Wemm } else
152d138df61SPeter Wemm fmt1 = optarg;
153d138df61SPeter Wemm break;
154b9ae52e3SPaul Richards default:
155b9ae52e3SPaul Richards usage();
156699e1b82SRich Murphey /* NOTREACHED */
157b9ae52e3SPaul Richards }
158b9ae52e3SPaul Richards }
159b9ae52e3SPaul Richards argc -= optind;
160b9ae52e3SPaul Richards argv += optind;
161b9ae52e3SPaul Richards
162b9ae52e3SPaul Richards if (argc <= 0) {
163b9ae52e3SPaul Richards usage();
164699e1b82SRich Murphey /* NOTREACHED */
165b9ae52e3SPaul Richards }
166b9ae52e3SPaul Richards
167699e1b82SRich Murphey rval = 0;
168e2daa140SJohn Polstra for (; argc > 0; argc--, argv++) {
169f48114b6SSimon J. Gerraty if ((fd = open(*argv, O_RDONLY | O_VERIFY, 0)) < 0) {
170699e1b82SRich Murphey warn("%s", *argv);
171b9ae52e3SPaul Richards rval |= 1;
172b9ae52e3SPaul Richards continue;
173b9ae52e3SPaul Richards }
174d3c1e14bSEdwin Groothuis rv = is_executable(*argv, fd, &is_shlib, &type);
175a0d476a9SEdwin Groothuis close(fd);
176d3c1e14bSEdwin Groothuis if (rv == 0) {
177c474c6d3SDoug Rabson rval |= 1;
178c474c6d3SDoug Rabson continue;
179c474c6d3SDoug Rabson }
180c474c6d3SDoug Rabson
181fffd993dSEdwin Groothuis switch (type) {
182fffd993dSEdwin Groothuis case TYPE_ELF:
183fffd993dSEdwin Groothuis break;
1848bd833ffSEdwin Groothuis #if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED)
185fffd993dSEdwin Groothuis case TYPE_ELF32:
18617fc43bcSKonstantin Belousov rval |= execldd32(*argv, fmt1, fmt2, aflag);
187e68ed793SJohn Baldwin continue;
188fffd993dSEdwin Groothuis #endif
189fffd993dSEdwin Groothuis case TYPE_UNKNOWN:
190fffd993dSEdwin Groothuis default:
191fffd993dSEdwin Groothuis /*
192fffd993dSEdwin Groothuis * This shouldn't happen unless is_executable()
193fffd993dSEdwin Groothuis * is broken.
194fffd993dSEdwin Groothuis */
195fffd993dSEdwin Groothuis errx(EDOOFUS, "unknown executable type");
196fffd993dSEdwin Groothuis }
197fffd993dSEdwin Groothuis
198d3c1e14bSEdwin Groothuis /* ld.so magic */
199a94a4b74SMark Johnston LDD_SETENV("TRACE_LOADED_OBJECTS", "yes", 1);
200d3c1e14bSEdwin Groothuis if (fmt1 != NULL)
201a94a4b74SMark Johnston LDD_SETENV("TRACE_LOADED_OBJECTS_FMT1", fmt1, 1);
202d3c1e14bSEdwin Groothuis if (fmt2 != NULL)
203a94a4b74SMark Johnston LDD_SETENV("TRACE_LOADED_OBJECTS_FMT2", fmt2, 1);
204a0d476a9SEdwin Groothuis
205a94a4b74SMark Johnston LDD_SETENV("TRACE_LOADED_OBJECTS_PROGNAME", *argv, 1);
206a0d476a9SEdwin Groothuis if (aflag)
207a94a4b74SMark Johnston LDD_SETENV("TRACE_LOADED_OBJECTS_ALL", "1", 1);
20820249943SDavid E. O'Brien else if (fmt1 == NULL && fmt2 == NULL)
209d138df61SPeter Wemm /* Default formats */
210b9ae52e3SPaul Richards printf("%s:\n", *argv);
21109e3d49dSJordan K. Hubbard fflush(stdout);
212b9ae52e3SPaul Richards
213b9ae52e3SPaul Richards switch (fork()) {
214b9ae52e3SPaul Richards case -1:
215699e1b82SRich Murphey err(1, "fork");
216b9ae52e3SPaul Richards break;
217b9ae52e3SPaul Richards default:
21852122f31SJohn Baldwin if (wait(&status) < 0) {
219699e1b82SRich Murphey warn("wait");
220699e1b82SRich Murphey rval |= 1;
221699e1b82SRich Murphey } else if (WIFSIGNALED(status)) {
222a0d476a9SEdwin Groothuis fprintf(stderr, "%s: signal %d\n", *argv,
223a0d476a9SEdwin Groothuis WTERMSIG(status));
224b9ae52e3SPaul Richards rval |= 1;
22552122f31SJohn Baldwin } else if (WIFEXITED(status) &&
22652122f31SJohn Baldwin WEXITSTATUS(status) != 0) {
227a0d476a9SEdwin Groothuis fprintf(stderr, "%s: exit status %d\n", *argv,
228a0d476a9SEdwin Groothuis WEXITSTATUS(status));
229b9ae52e3SPaul Richards rval |= 1;
230b9ae52e3SPaul Richards }
231b9ae52e3SPaul Richards break;
232b9ae52e3SPaul Richards case 0:
2332c7a6dadSKonstantin Belousov rtld = _PATH_RTLD;
2342c7a6dadSKonstantin Belousov #if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED)
2352c7a6dadSKonstantin Belousov if (type == TYPE_ELF32)
236*e17dd921SJessica Clarke rtld = __PATH_RTLD("32");
2372c7a6dadSKonstantin Belousov #endif
2389cabef3dSKonstantin Belousov if (is_shlib == 0) {
2399cabef3dSKonstantin Belousov execl(rtld, rtld, "--",
2409cabef3dSKonstantin Belousov *argv, (char *)NULL);
2419cabef3dSKonstantin Belousov warn("%s", *argv);
2429cabef3dSKonstantin Belousov } else if (fmt1 == NULL && fmt2 == NULL && !aflag) {
2439cabef3dSKonstantin Belousov dlopen(*argv, RTLD_TRACE);
2449cabef3dSKonstantin Belousov warnx("%s: %s", *argv, dlerror());
2459cabef3dSKonstantin Belousov } else {
2462c7a6dadSKonstantin Belousov execl(rtld, rtld, "-d", "--",
2472c7a6dadSKonstantin Belousov *argv, (char *)NULL);
248c6de4ce7SMaxim Sobolev }
249b9ae52e3SPaul Richards _exit(1);
250b9ae52e3SPaul Richards }
251b9ae52e3SPaul Richards }
252b9ae52e3SPaul Richards
253ca8c576dSKonstantin Belousov return (rval);
254b9ae52e3SPaul Richards }
255d3c1e14bSEdwin Groothuis
256d3c1e14bSEdwin Groothuis static void
usage(void)257d3c1e14bSEdwin Groothuis usage(void)
258d3c1e14bSEdwin Groothuis {
259d3c1e14bSEdwin Groothuis
260e9f8723cSEd Maste fprintf(stderr,
261e9f8723cSEd Maste "usage: ldd [-a] [-f format [-f format]] program ...\n");
262d3c1e14bSEdwin Groothuis exit(1);
263d3c1e14bSEdwin Groothuis }
264d3c1e14bSEdwin Groothuis
2659d4104b2SJohn Baldwin static bool
has_freebsd_abi_tag(const char * fname,Elf * elf,GElf_Ehdr * ehdr,off_t offset,size_t len)2669d4104b2SJohn Baldwin has_freebsd_abi_tag(const char *fname, Elf *elf, GElf_Ehdr *ehdr, off_t offset,
2679d4104b2SJohn Baldwin size_t len)
2689d4104b2SJohn Baldwin {
2699d4104b2SJohn Baldwin Elf_Data dst, src;
2709d4104b2SJohn Baldwin const Elf_Note *note;
2719d4104b2SJohn Baldwin char *buf;
2729d4104b2SJohn Baldwin const char *name;
2739d4104b2SJohn Baldwin void *copy;
2749d4104b2SJohn Baldwin size_t namesz, descsz;
2759d4104b2SJohn Baldwin bool has_abi_tag;
2769d4104b2SJohn Baldwin
2779d4104b2SJohn Baldwin buf = elf_rawfile(elf, NULL);
2789d4104b2SJohn Baldwin if (buf == NULL) {
2799d4104b2SJohn Baldwin warnx("%s: %s", fname, elf_errmsg(0));
2809d4104b2SJohn Baldwin return (false);
2819d4104b2SJohn Baldwin }
2829d4104b2SJohn Baldwin
2839d4104b2SJohn Baldwin memset(&src, 0, sizeof(src));
2849d4104b2SJohn Baldwin src.d_buf = buf + offset;
2859d4104b2SJohn Baldwin src.d_size = len;
2869d4104b2SJohn Baldwin src.d_type = ELF_T_NOTE;
2879d4104b2SJohn Baldwin src.d_version = EV_CURRENT;
2889d4104b2SJohn Baldwin
2899d4104b2SJohn Baldwin memset(&dst, 0, sizeof(dst));
2909d4104b2SJohn Baldwin dst.d_buf = copy = malloc(len);
2919d4104b2SJohn Baldwin dst.d_size = len;
2929d4104b2SJohn Baldwin dst.d_type = ELF_T_NOTE;
2939d4104b2SJohn Baldwin dst.d_version = EV_CURRENT;
2949d4104b2SJohn Baldwin
2959d4104b2SJohn Baldwin if (gelf_xlatetom(elf, &dst, &src, ehdr->e_ident[EI_DATA]) == NULL) {
2969d4104b2SJohn Baldwin warnx("%s: failed to parse notes: %s", fname, elf_errmsg(0));
2979d4104b2SJohn Baldwin free(copy);
2989d4104b2SJohn Baldwin return (false);
2999d4104b2SJohn Baldwin }
3009d4104b2SJohn Baldwin
3019d4104b2SJohn Baldwin buf = copy;
3029d4104b2SJohn Baldwin has_abi_tag = false;
3039d4104b2SJohn Baldwin for (;;) {
3049d4104b2SJohn Baldwin if (len < sizeof(*note))
3059d4104b2SJohn Baldwin break;
3069d4104b2SJohn Baldwin
3079d4104b2SJohn Baldwin note = (const void *)buf;
3089d4104b2SJohn Baldwin buf += sizeof(*note);
3099d4104b2SJohn Baldwin len -= sizeof(*note);
3109d4104b2SJohn Baldwin
3119d4104b2SJohn Baldwin namesz = roundup2(note->n_namesz, sizeof(uint32_t));
3129d4104b2SJohn Baldwin descsz = roundup2(note->n_descsz, sizeof(uint32_t));
3139d4104b2SJohn Baldwin if (len < namesz + descsz)
3149d4104b2SJohn Baldwin break;
3159d4104b2SJohn Baldwin
3169d4104b2SJohn Baldwin name = buf;
3179d4104b2SJohn Baldwin if (note->n_namesz == sizeof(ELF_NOTE_FREEBSD) &&
3189d4104b2SJohn Baldwin strncmp(name, ELF_NOTE_FREEBSD, note->n_namesz) == 0 &&
3199d4104b2SJohn Baldwin note->n_type == NT_FREEBSD_ABI_TAG &&
3209d4104b2SJohn Baldwin note->n_descsz == sizeof(uint32_t)) {
3219d4104b2SJohn Baldwin has_abi_tag = true;
3229d4104b2SJohn Baldwin break;
3239d4104b2SJohn Baldwin }
3249d4104b2SJohn Baldwin
3259d4104b2SJohn Baldwin buf += namesz + descsz;
3269d4104b2SJohn Baldwin len -= namesz + descsz;
3279d4104b2SJohn Baldwin }
3289d4104b2SJohn Baldwin
3299d4104b2SJohn Baldwin free(copy);
3309d4104b2SJohn Baldwin return (has_abi_tag);
3319d4104b2SJohn Baldwin }
3329d4104b2SJohn Baldwin
3339d4104b2SJohn Baldwin static bool
is_pie(const char * fname,Elf * elf,GElf_Ehdr * ehdr,off_t offset,size_t len)3349d4104b2SJohn Baldwin is_pie(const char *fname, Elf *elf, GElf_Ehdr *ehdr, off_t offset, size_t len)
3359d4104b2SJohn Baldwin {
3369d4104b2SJohn Baldwin Elf_Data dst, src;
3379d4104b2SJohn Baldwin char *buf;
3389d4104b2SJohn Baldwin void *copy;
3399d4104b2SJohn Baldwin const GElf_Dyn *dyn;
3409d4104b2SJohn Baldwin size_t dynsize;
3419d4104b2SJohn Baldwin u_int count, i;
3429d4104b2SJohn Baldwin bool pie;
3439d4104b2SJohn Baldwin
3449d4104b2SJohn Baldwin buf = elf_rawfile(elf, NULL);
3459d4104b2SJohn Baldwin if (buf == NULL) {
3469d4104b2SJohn Baldwin warnx("%s: %s", fname, elf_errmsg(0));
3479d4104b2SJohn Baldwin return (false);
3489d4104b2SJohn Baldwin }
3499d4104b2SJohn Baldwin
3509d4104b2SJohn Baldwin dynsize = gelf_fsize(elf, ELF_T_DYN, 1, EV_CURRENT);
3519d4104b2SJohn Baldwin if (dynsize == 0) {
3529d4104b2SJohn Baldwin warnx("%s: %s", fname, elf_errmsg(0));
3539d4104b2SJohn Baldwin return (false);
3549d4104b2SJohn Baldwin }
3559d4104b2SJohn Baldwin count = len / dynsize;
3569d4104b2SJohn Baldwin
3579d4104b2SJohn Baldwin memset(&src, 0, sizeof(src));
3589d4104b2SJohn Baldwin src.d_buf = buf + offset;
3599d4104b2SJohn Baldwin src.d_size = len;
3609d4104b2SJohn Baldwin src.d_type = ELF_T_DYN;
3619d4104b2SJohn Baldwin src.d_version = EV_CURRENT;
3629d4104b2SJohn Baldwin
3639d4104b2SJohn Baldwin memset(&dst, 0, sizeof(dst));
3649d4104b2SJohn Baldwin dst.d_buf = copy = malloc(count * sizeof(*dyn));
3659d4104b2SJohn Baldwin dst.d_size = count * sizeof(*dyn);
3669d4104b2SJohn Baldwin dst.d_type = ELF_T_DYN;
3679d4104b2SJohn Baldwin dst.d_version = EV_CURRENT;
3689d4104b2SJohn Baldwin
3699d4104b2SJohn Baldwin if (gelf_xlatetom(elf, &dst, &src, ehdr->e_ident[EI_DATA]) == NULL) {
3709d4104b2SJohn Baldwin warnx("%s: failed to parse .dynamic: %s", fname, elf_errmsg(0));
3719d4104b2SJohn Baldwin free(copy);
3729d4104b2SJohn Baldwin return (false);
3739d4104b2SJohn Baldwin }
3749d4104b2SJohn Baldwin
3759d4104b2SJohn Baldwin dyn = copy;
3769d4104b2SJohn Baldwin pie = false;
3779d4104b2SJohn Baldwin for (i = 0; i < count; i++) {
3789d4104b2SJohn Baldwin if (dyn[i].d_tag != DT_FLAGS_1)
3799d4104b2SJohn Baldwin continue;
3809d4104b2SJohn Baldwin
3819d4104b2SJohn Baldwin pie = (dyn[i].d_un.d_val & DF_1_PIE) != 0;
3829d4104b2SJohn Baldwin break;
3839d4104b2SJohn Baldwin }
3849d4104b2SJohn Baldwin
3859d4104b2SJohn Baldwin free(copy);
3869d4104b2SJohn Baldwin return (pie);
3879d4104b2SJohn Baldwin }
3889d4104b2SJohn Baldwin
389d3c1e14bSEdwin Groothuis static int
is_executable(const char * fname,int fd,int * is_shlib,int * type)390d3c1e14bSEdwin Groothuis is_executable(const char *fname, int fd, int *is_shlib, int *type)
391d3c1e14bSEdwin Groothuis {
3929d4104b2SJohn Baldwin Elf *elf;
3939d4104b2SJohn Baldwin GElf_Ehdr ehdr;
3949d4104b2SJohn Baldwin GElf_Phdr phdr;
3959d4104b2SJohn Baldwin bool dynamic, freebsd, pie;
3969d4104b2SJohn Baldwin int i;
397d3c1e14bSEdwin Groothuis
398d3c1e14bSEdwin Groothuis *is_shlib = 0;
399d3c1e14bSEdwin Groothuis *type = TYPE_UNKNOWN;
4009d4104b2SJohn Baldwin dynamic = false;
4019d4104b2SJohn Baldwin freebsd = false;
4029d4104b2SJohn Baldwin pie = false;
403d3c1e14bSEdwin Groothuis
4049d4104b2SJohn Baldwin if (elf_version(EV_CURRENT) == EV_NONE) {
4059d4104b2SJohn Baldwin warnx("unsupported libelf");
406d3c1e14bSEdwin Groothuis return (0);
407d3c1e14bSEdwin Groothuis }
4089d4104b2SJohn Baldwin elf = elf_begin(fd, ELF_C_READ, NULL);
4099d4104b2SJohn Baldwin if (elf == NULL) {
4109d4104b2SJohn Baldwin warnx("%s: %s", fname, elf_errmsg(0));
411fffd993dSEdwin Groothuis return (0);
412fffd993dSEdwin Groothuis }
4139d4104b2SJohn Baldwin if (elf_kind(elf) != ELF_K_ELF) {
4149d4104b2SJohn Baldwin elf_end(elf);
415fffd993dSEdwin Groothuis warnx("%s: not a dynamic ELF executable", fname);
416fffd993dSEdwin Groothuis return (0);
417fffd993dSEdwin Groothuis }
4189d4104b2SJohn Baldwin if (gelf_getehdr(elf, &ehdr) == NULL) {
4199d4104b2SJohn Baldwin warnx("%s: %s", fname, elf_errmsg(0));
4209d4104b2SJohn Baldwin elf_end(elf);
421fffd993dSEdwin Groothuis return (0);
422fffd993dSEdwin Groothuis }
423fffd993dSEdwin Groothuis
424d3c1e14bSEdwin Groothuis *type = TYPE_ELF;
4259d4104b2SJohn Baldwin #if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED)
4269d4104b2SJohn Baldwin if (gelf_getclass(elf) == ELFCLASS32) {
4279d4104b2SJohn Baldwin *type = TYPE_ELF32;
4289d4104b2SJohn Baldwin }
4299d4104b2SJohn Baldwin #endif
430d3c1e14bSEdwin Groothuis
4319d4104b2SJohn Baldwin freebsd = ehdr.e_ident[EI_OSABI] == ELFOSABI_FREEBSD;
4329d4104b2SJohn Baldwin for (i = 0; i < ehdr.e_phnum; i++) {
4339d4104b2SJohn Baldwin if (gelf_getphdr(elf, i, &phdr) == NULL) {
4349d4104b2SJohn Baldwin warnx("%s: %s", fname, elf_errmsg(0));
4359d4104b2SJohn Baldwin elf_end(elf);
436d3c1e14bSEdwin Groothuis return (0);
437d3c1e14bSEdwin Groothuis }
4389d4104b2SJohn Baldwin switch (phdr.p_type) {
4399d4104b2SJohn Baldwin case PT_NOTE:
4409d4104b2SJohn Baldwin if (ehdr.e_ident[EI_OSABI] == ELFOSABI_NONE && !freebsd)
4419d4104b2SJohn Baldwin freebsd = has_freebsd_abi_tag(fname, elf, &ehdr,
4429d4104b2SJohn Baldwin phdr.p_offset, phdr.p_filesz);
4439d4104b2SJohn Baldwin break;
4449d4104b2SJohn Baldwin case PT_DYNAMIC:
4459d4104b2SJohn Baldwin dynamic = true;
4469d4104b2SJohn Baldwin if (ehdr.e_type == ET_DYN)
4479d4104b2SJohn Baldwin pie = is_pie(fname, elf, &ehdr, phdr.p_offset,
4489d4104b2SJohn Baldwin phdr.p_filesz);
449d3c1e14bSEdwin Groothuis break;
450d3c1e14bSEdwin Groothuis }
451d3c1e14bSEdwin Groothuis }
452d3c1e14bSEdwin Groothuis
453d3c1e14bSEdwin Groothuis if (!dynamic) {
4549d4104b2SJohn Baldwin elf_end(elf);
455d3c1e14bSEdwin Groothuis warnx("%s: not a dynamic ELF executable", fname);
456d3c1e14bSEdwin Groothuis return (0);
457d3c1e14bSEdwin Groothuis }
4582b5d88fdSKonstantin Belousov
4599d4104b2SJohn Baldwin if (ehdr.e_type == ET_DYN && !pie) {
4609d4104b2SJohn Baldwin *is_shlib = 1;
4612b5d88fdSKonstantin Belousov
4629d4104b2SJohn Baldwin if (!freebsd) {
4639d4104b2SJohn Baldwin elf_end(elf);
464d3c1e14bSEdwin Groothuis warnx("%s: not a FreeBSD ELF shared object", fname);
465d3c1e14bSEdwin Groothuis return (0);
466d3c1e14bSEdwin Groothuis }
467d3c1e14bSEdwin Groothuis }
468d3c1e14bSEdwin Groothuis
4699d4104b2SJohn Baldwin elf_end(elf);
4709d4104b2SJohn Baldwin return (1);
471d3c1e14bSEdwin Groothuis }
472