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 369d4104b2SJohn 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> 479d4104b2SJohn Baldwin #include <gelf.h> 489d4104b2SJohn Baldwin #include <libelf.h> 492c7a6dadSKonstantin Belousov #include <rtld_paths.h> 509d4104b2SJohn Baldwin #include <stdbool.h> 51699e1b82SRich Murphey #include <stdio.h> 52699e1b82SRich Murphey #include <stdlib.h> 53e68ed793SJohn Baldwin #include <string.h> 54699e1b82SRich Murphey #include <unistd.h> 55b9ae52e3SPaul Richards 568bd833ffSEdwin Groothuis /* 57bff71350SEdwin Groothuis * 32-bit ELF data structures can only be used if the system header[s] declare 58bff71350SEdwin Groothuis * them. There is no official macro for determining whether they are declared, 59bff71350SEdwin Groothuis * so check for the existence of one of the 32-macros defined in elf(5). 608bd833ffSEdwin Groothuis */ 61bff71350SEdwin Groothuis #ifdef ELF32_R_TYPE 628bd833ffSEdwin Groothuis #define ELF32_SUPPORTED 638bd833ffSEdwin Groothuis #endif 648bd833ffSEdwin Groothuis 65a94a4b74SMark Johnston #define LDD_SETENV(name, value, overwrite) do { \ 66a94a4b74SMark Johnston setenv("LD_" name, value, overwrite); \ 67a94a4b74SMark Johnston setenv("LD_32_" name, value, overwrite); \ 68a94a4b74SMark Johnston } while (0) 69a94a4b74SMark Johnston 70a94a4b74SMark Johnston #define LDD_UNSETENV(name) do { \ 71a94a4b74SMark Johnston unsetenv("LD_" name); \ 72a94a4b74SMark Johnston unsetenv("LD_32_" name); \ 73a94a4b74SMark Johnston } while (0) 74a94a4b74SMark Johnston 75d3c1e14bSEdwin Groothuis static int is_executable(const char *fname, int fd, int *is_shlib, 76d3c1e14bSEdwin Groothuis int *type); 77d3c1e14bSEdwin Groothuis static void usage(void); 78a0d476a9SEdwin Groothuis 79d3c1e14bSEdwin Groothuis #define TYPE_UNKNOWN 0 80c8eee7c0SEd Maste #define TYPE_ELF 1 /* Architecture default */ 818bd833ffSEdwin Groothuis #if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED) 82c8eee7c0SEd Maste #define TYPE_ELF32 2 /* Explicit 32 bits on architectures >32 bits */ 83d3c1e14bSEdwin Groothuis 84e68ed793SJohn Baldwin #define _PATH_LDD32 "/usr/bin/ldd32" 85d3c1e14bSEdwin Groothuis 86e68ed793SJohn Baldwin static int 8717fc43bcSKonstantin Belousov execldd32(char *file, char *fmt1, char *fmt2, int aflag) 88e68ed793SJohn Baldwin { 894b426307SDon Lewis char *argv[9]; 90e68ed793SJohn Baldwin int i, rval, status; 91e68ed793SJohn Baldwin 92a94a4b74SMark Johnston LDD_UNSETENV("TRACE_LOADED_OBJECTS"); 93e68ed793SJohn Baldwin rval = 0; 94e68ed793SJohn Baldwin i = 0; 95e68ed793SJohn Baldwin argv[i++] = strdup(_PATH_LDD32); 96e68ed793SJohn Baldwin if (aflag) 97e68ed793SJohn Baldwin argv[i++] = strdup("-a"); 9852122f31SJohn Baldwin if (fmt1 != NULL) { 99e68ed793SJohn Baldwin argv[i++] = strdup("-f"); 100e68ed793SJohn Baldwin argv[i++] = strdup(fmt1); 101e68ed793SJohn Baldwin } 10252122f31SJohn Baldwin if (fmt2 != NULL) { 103e68ed793SJohn Baldwin argv[i++] = strdup("-f"); 104e68ed793SJohn Baldwin argv[i++] = strdup(fmt2); 105e68ed793SJohn Baldwin } 106e68ed793SJohn Baldwin argv[i++] = strdup(file); 107e68ed793SJohn Baldwin argv[i++] = NULL; 108e68ed793SJohn Baldwin 109e68ed793SJohn Baldwin switch (fork()) { 110e68ed793SJohn Baldwin case -1: 111e68ed793SJohn Baldwin err(1, "fork"); 112e68ed793SJohn Baldwin break; 113e68ed793SJohn Baldwin case 0: 114e68ed793SJohn Baldwin execv(_PATH_LDD32, argv); 115e68ed793SJohn Baldwin warn("%s", _PATH_LDD32); 11652122f31SJohn Baldwin _exit(127); 117e68ed793SJohn Baldwin break; 118e68ed793SJohn Baldwin default: 11952122f31SJohn Baldwin if (wait(&status) < 0) 120e68ed793SJohn Baldwin rval = 1; 12152122f31SJohn Baldwin else if (WIFSIGNALED(status)) 122e68ed793SJohn Baldwin rval = 1; 12352122f31SJohn Baldwin else if (WIFEXITED(status) && WEXITSTATUS(status) != 0) 124e68ed793SJohn Baldwin rval = 1; 125e68ed793SJohn Baldwin break; 126e68ed793SJohn Baldwin } 127e68ed793SJohn Baldwin while (i--) 128e68ed793SJohn Baldwin free(argv[i]); 129a94a4b74SMark Johnston LDD_SETENV("TRACE_LOADED_OBJECTS", "yes", 1); 130e68ed793SJohn Baldwin return (rval); 131e68ed793SJohn Baldwin } 132fffd993dSEdwin Groothuis #endif 133b9ae52e3SPaul Richards 134b9ae52e3SPaul Richards int 135a53809fdSMark Murray main(int argc, char *argv[]) 136b9ae52e3SPaul Richards { 137a0d476a9SEdwin Groothuis char *fmt1, *fmt2; 1382c7a6dadSKonstantin Belousov const char *rtld; 139ca8c576dSKonstantin Belousov int aflag, c, fd, rval, status, is_shlib, rv, type; 140b9ae52e3SPaul Richards 14117fc43bcSKonstantin Belousov aflag = 0; 142a0d476a9SEdwin Groothuis fmt1 = fmt2 = NULL; 14320249943SDavid E. O'Brien 14417fc43bcSKonstantin Belousov while ((c = getopt(argc, argv, "af:")) != -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; 157b9ae52e3SPaul Richards default: 158b9ae52e3SPaul Richards usage(); 159699e1b82SRich Murphey /* NOTREACHED */ 160b9ae52e3SPaul Richards } 161b9ae52e3SPaul Richards } 162b9ae52e3SPaul Richards argc -= optind; 163b9ae52e3SPaul Richards argv += optind; 164b9ae52e3SPaul Richards 165b9ae52e3SPaul Richards if (argc <= 0) { 166b9ae52e3SPaul Richards usage(); 167699e1b82SRich Murphey /* NOTREACHED */ 168b9ae52e3SPaul Richards } 169b9ae52e3SPaul Richards 170699e1b82SRich Murphey rval = 0; 171e2daa140SJohn Polstra for (; argc > 0; argc--, argv++) { 172*f48114b6SSimon J. Gerraty if ((fd = open(*argv, O_RDONLY | O_VERIFY, 0)) < 0) { 173699e1b82SRich Murphey warn("%s", *argv); 174b9ae52e3SPaul Richards rval |= 1; 175b9ae52e3SPaul Richards continue; 176b9ae52e3SPaul Richards } 177d3c1e14bSEdwin Groothuis rv = is_executable(*argv, fd, &is_shlib, &type); 178a0d476a9SEdwin Groothuis close(fd); 179d3c1e14bSEdwin Groothuis if (rv == 0) { 180c474c6d3SDoug Rabson rval |= 1; 181c474c6d3SDoug Rabson continue; 182c474c6d3SDoug Rabson } 183c474c6d3SDoug Rabson 184fffd993dSEdwin Groothuis switch (type) { 185fffd993dSEdwin Groothuis case TYPE_ELF: 186fffd993dSEdwin Groothuis break; 1878bd833ffSEdwin Groothuis #if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED) 188fffd993dSEdwin Groothuis case TYPE_ELF32: 18917fc43bcSKonstantin Belousov rval |= execldd32(*argv, fmt1, fmt2, aflag); 190e68ed793SJohn Baldwin continue; 191fffd993dSEdwin Groothuis #endif 192fffd993dSEdwin Groothuis case TYPE_UNKNOWN: 193fffd993dSEdwin Groothuis default: 194fffd993dSEdwin Groothuis /* 195fffd993dSEdwin Groothuis * This shouldn't happen unless is_executable() 196fffd993dSEdwin Groothuis * is broken. 197fffd993dSEdwin Groothuis */ 198fffd993dSEdwin Groothuis errx(EDOOFUS, "unknown executable type"); 199fffd993dSEdwin Groothuis } 200fffd993dSEdwin Groothuis 201d3c1e14bSEdwin Groothuis /* ld.so magic */ 202a94a4b74SMark Johnston LDD_SETENV("TRACE_LOADED_OBJECTS", "yes", 1); 203d3c1e14bSEdwin Groothuis if (fmt1 != NULL) 204a94a4b74SMark Johnston LDD_SETENV("TRACE_LOADED_OBJECTS_FMT1", fmt1, 1); 205d3c1e14bSEdwin Groothuis if (fmt2 != NULL) 206a94a4b74SMark Johnston LDD_SETENV("TRACE_LOADED_OBJECTS_FMT2", fmt2, 1); 207a0d476a9SEdwin Groothuis 208a94a4b74SMark Johnston LDD_SETENV("TRACE_LOADED_OBJECTS_PROGNAME", *argv, 1); 209a0d476a9SEdwin Groothuis if (aflag) 210a94a4b74SMark Johnston LDD_SETENV("TRACE_LOADED_OBJECTS_ALL", "1", 1); 21120249943SDavid E. O'Brien else if (fmt1 == NULL && fmt2 == NULL) 212d138df61SPeter Wemm /* Default formats */ 213b9ae52e3SPaul Richards printf("%s:\n", *argv); 21409e3d49dSJordan K. Hubbard fflush(stdout); 215b9ae52e3SPaul Richards 216b9ae52e3SPaul Richards switch (fork()) { 217b9ae52e3SPaul Richards case -1: 218699e1b82SRich Murphey err(1, "fork"); 219b9ae52e3SPaul Richards break; 220b9ae52e3SPaul Richards default: 22152122f31SJohn Baldwin if (wait(&status) < 0) { 222699e1b82SRich Murphey warn("wait"); 223699e1b82SRich Murphey rval |= 1; 224699e1b82SRich Murphey } else if (WIFSIGNALED(status)) { 225a0d476a9SEdwin Groothuis fprintf(stderr, "%s: signal %d\n", *argv, 226a0d476a9SEdwin Groothuis WTERMSIG(status)); 227b9ae52e3SPaul Richards rval |= 1; 22852122f31SJohn Baldwin } else if (WIFEXITED(status) && 22952122f31SJohn Baldwin WEXITSTATUS(status) != 0) { 230a0d476a9SEdwin Groothuis fprintf(stderr, "%s: exit status %d\n", *argv, 231a0d476a9SEdwin Groothuis WEXITSTATUS(status)); 232b9ae52e3SPaul Richards rval |= 1; 233b9ae52e3SPaul Richards } 234b9ae52e3SPaul Richards break; 235b9ae52e3SPaul Richards case 0: 2362c7a6dadSKonstantin Belousov rtld = _PATH_RTLD; 2372c7a6dadSKonstantin Belousov #if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED) 2382c7a6dadSKonstantin Belousov if (type == TYPE_ELF32) 2392c7a6dadSKonstantin Belousov rtld = _COMPAT32_PATH_RTLD; 2402c7a6dadSKonstantin Belousov #endif 2419cabef3dSKonstantin Belousov if (is_shlib == 0) { 2429cabef3dSKonstantin Belousov execl(rtld, rtld, "--", 2439cabef3dSKonstantin Belousov *argv, (char *)NULL); 2449cabef3dSKonstantin Belousov warn("%s", *argv); 2459cabef3dSKonstantin Belousov } else if (fmt1 == NULL && fmt2 == NULL && !aflag) { 2469cabef3dSKonstantin Belousov dlopen(*argv, RTLD_TRACE); 2479cabef3dSKonstantin Belousov warnx("%s: %s", *argv, dlerror()); 2489cabef3dSKonstantin Belousov } else { 2492c7a6dadSKonstantin Belousov execl(rtld, rtld, "-d", "--", 2502c7a6dadSKonstantin Belousov *argv, (char *)NULL); 251c6de4ce7SMaxim Sobolev } 252b9ae52e3SPaul Richards _exit(1); 253b9ae52e3SPaul Richards } 254b9ae52e3SPaul Richards } 255b9ae52e3SPaul Richards 256ca8c576dSKonstantin Belousov return (rval); 257b9ae52e3SPaul Richards } 258d3c1e14bSEdwin Groothuis 259d3c1e14bSEdwin Groothuis static void 260d3c1e14bSEdwin Groothuis usage(void) 261d3c1e14bSEdwin Groothuis { 262d3c1e14bSEdwin Groothuis 26317fc43bcSKonstantin Belousov fprintf(stderr, "usage: ldd [-a] [-f format] program ...\n"); 264d3c1e14bSEdwin Groothuis exit(1); 265d3c1e14bSEdwin Groothuis } 266d3c1e14bSEdwin Groothuis 2679d4104b2SJohn Baldwin static bool 2689d4104b2SJohn Baldwin has_freebsd_abi_tag(const char *fname, Elf *elf, GElf_Ehdr *ehdr, off_t offset, 2699d4104b2SJohn Baldwin size_t len) 2709d4104b2SJohn Baldwin { 2719d4104b2SJohn Baldwin Elf_Data dst, src; 2729d4104b2SJohn Baldwin const Elf_Note *note; 2739d4104b2SJohn Baldwin char *buf; 2749d4104b2SJohn Baldwin const char *name; 2759d4104b2SJohn Baldwin void *copy; 2769d4104b2SJohn Baldwin size_t namesz, descsz; 2779d4104b2SJohn Baldwin bool has_abi_tag; 2789d4104b2SJohn Baldwin 2799d4104b2SJohn Baldwin buf = elf_rawfile(elf, NULL); 2809d4104b2SJohn Baldwin if (buf == NULL) { 2819d4104b2SJohn Baldwin warnx("%s: %s", fname, elf_errmsg(0)); 2829d4104b2SJohn Baldwin return (false); 2839d4104b2SJohn Baldwin } 2849d4104b2SJohn Baldwin 2859d4104b2SJohn Baldwin memset(&src, 0, sizeof(src)); 2869d4104b2SJohn Baldwin src.d_buf = buf + offset; 2879d4104b2SJohn Baldwin src.d_size = len; 2889d4104b2SJohn Baldwin src.d_type = ELF_T_NOTE; 2899d4104b2SJohn Baldwin src.d_version = EV_CURRENT; 2909d4104b2SJohn Baldwin 2919d4104b2SJohn Baldwin memset(&dst, 0, sizeof(dst)); 2929d4104b2SJohn Baldwin dst.d_buf = copy = malloc(len); 2939d4104b2SJohn Baldwin dst.d_size = len; 2949d4104b2SJohn Baldwin dst.d_type = ELF_T_NOTE; 2959d4104b2SJohn Baldwin dst.d_version = EV_CURRENT; 2969d4104b2SJohn Baldwin 2979d4104b2SJohn Baldwin if (gelf_xlatetom(elf, &dst, &src, ehdr->e_ident[EI_DATA]) == NULL) { 2989d4104b2SJohn Baldwin warnx("%s: failed to parse notes: %s", fname, elf_errmsg(0)); 2999d4104b2SJohn Baldwin free(copy); 3009d4104b2SJohn Baldwin return (false); 3019d4104b2SJohn Baldwin } 3029d4104b2SJohn Baldwin 3039d4104b2SJohn Baldwin buf = copy; 3049d4104b2SJohn Baldwin has_abi_tag = false; 3059d4104b2SJohn Baldwin for (;;) { 3069d4104b2SJohn Baldwin if (len < sizeof(*note)) 3079d4104b2SJohn Baldwin break; 3089d4104b2SJohn Baldwin 3099d4104b2SJohn Baldwin note = (const void *)buf; 3109d4104b2SJohn Baldwin buf += sizeof(*note); 3119d4104b2SJohn Baldwin len -= sizeof(*note); 3129d4104b2SJohn Baldwin 3139d4104b2SJohn Baldwin namesz = roundup2(note->n_namesz, sizeof(uint32_t)); 3149d4104b2SJohn Baldwin descsz = roundup2(note->n_descsz, sizeof(uint32_t)); 3159d4104b2SJohn Baldwin if (len < namesz + descsz) 3169d4104b2SJohn Baldwin break; 3179d4104b2SJohn Baldwin 3189d4104b2SJohn Baldwin name = buf; 3199d4104b2SJohn Baldwin if (note->n_namesz == sizeof(ELF_NOTE_FREEBSD) && 3209d4104b2SJohn Baldwin strncmp(name, ELF_NOTE_FREEBSD, note->n_namesz) == 0 && 3219d4104b2SJohn Baldwin note->n_type == NT_FREEBSD_ABI_TAG && 3229d4104b2SJohn Baldwin note->n_descsz == sizeof(uint32_t)) { 3239d4104b2SJohn Baldwin has_abi_tag = true; 3249d4104b2SJohn Baldwin break; 3259d4104b2SJohn Baldwin } 3269d4104b2SJohn Baldwin 3279d4104b2SJohn Baldwin buf += namesz + descsz; 3289d4104b2SJohn Baldwin len -= namesz + descsz; 3299d4104b2SJohn Baldwin } 3309d4104b2SJohn Baldwin 3319d4104b2SJohn Baldwin free(copy); 3329d4104b2SJohn Baldwin return (has_abi_tag); 3339d4104b2SJohn Baldwin } 3349d4104b2SJohn Baldwin 3359d4104b2SJohn Baldwin static bool 3369d4104b2SJohn Baldwin is_pie(const char *fname, Elf *elf, GElf_Ehdr *ehdr, off_t offset, size_t len) 3379d4104b2SJohn Baldwin { 3389d4104b2SJohn Baldwin Elf_Data dst, src; 3399d4104b2SJohn Baldwin char *buf; 3409d4104b2SJohn Baldwin void *copy; 3419d4104b2SJohn Baldwin const GElf_Dyn *dyn; 3429d4104b2SJohn Baldwin size_t dynsize; 3439d4104b2SJohn Baldwin u_int count, i; 3449d4104b2SJohn Baldwin bool pie; 3459d4104b2SJohn Baldwin 3469d4104b2SJohn Baldwin buf = elf_rawfile(elf, NULL); 3479d4104b2SJohn Baldwin if (buf == NULL) { 3489d4104b2SJohn Baldwin warnx("%s: %s", fname, elf_errmsg(0)); 3499d4104b2SJohn Baldwin return (false); 3509d4104b2SJohn Baldwin } 3519d4104b2SJohn Baldwin 3529d4104b2SJohn Baldwin dynsize = gelf_fsize(elf, ELF_T_DYN, 1, EV_CURRENT); 3539d4104b2SJohn Baldwin if (dynsize == 0) { 3549d4104b2SJohn Baldwin warnx("%s: %s", fname, elf_errmsg(0)); 3559d4104b2SJohn Baldwin return (false); 3569d4104b2SJohn Baldwin } 3579d4104b2SJohn Baldwin count = len / dynsize; 3589d4104b2SJohn Baldwin 3599d4104b2SJohn Baldwin memset(&src, 0, sizeof(src)); 3609d4104b2SJohn Baldwin src.d_buf = buf + offset; 3619d4104b2SJohn Baldwin src.d_size = len; 3629d4104b2SJohn Baldwin src.d_type = ELF_T_DYN; 3639d4104b2SJohn Baldwin src.d_version = EV_CURRENT; 3649d4104b2SJohn Baldwin 3659d4104b2SJohn Baldwin memset(&dst, 0, sizeof(dst)); 3669d4104b2SJohn Baldwin dst.d_buf = copy = malloc(count * sizeof(*dyn)); 3679d4104b2SJohn Baldwin dst.d_size = count * sizeof(*dyn); 3689d4104b2SJohn Baldwin dst.d_type = ELF_T_DYN; 3699d4104b2SJohn Baldwin dst.d_version = EV_CURRENT; 3709d4104b2SJohn Baldwin 3719d4104b2SJohn Baldwin if (gelf_xlatetom(elf, &dst, &src, ehdr->e_ident[EI_DATA]) == NULL) { 3729d4104b2SJohn Baldwin warnx("%s: failed to parse .dynamic: %s", fname, elf_errmsg(0)); 3739d4104b2SJohn Baldwin free(copy); 3749d4104b2SJohn Baldwin return (false); 3759d4104b2SJohn Baldwin } 3769d4104b2SJohn Baldwin 3779d4104b2SJohn Baldwin dyn = copy; 3789d4104b2SJohn Baldwin pie = false; 3799d4104b2SJohn Baldwin for (i = 0; i < count; i++) { 3809d4104b2SJohn Baldwin if (dyn[i].d_tag != DT_FLAGS_1) 3819d4104b2SJohn Baldwin continue; 3829d4104b2SJohn Baldwin 3839d4104b2SJohn Baldwin pie = (dyn[i].d_un.d_val & DF_1_PIE) != 0; 3849d4104b2SJohn Baldwin break; 3859d4104b2SJohn Baldwin } 3869d4104b2SJohn Baldwin 3879d4104b2SJohn Baldwin free(copy); 3889d4104b2SJohn Baldwin return (pie); 3899d4104b2SJohn Baldwin } 3909d4104b2SJohn Baldwin 391d3c1e14bSEdwin Groothuis static int 392d3c1e14bSEdwin Groothuis is_executable(const char *fname, int fd, int *is_shlib, int *type) 393d3c1e14bSEdwin Groothuis { 3949d4104b2SJohn Baldwin Elf *elf; 3959d4104b2SJohn Baldwin GElf_Ehdr ehdr; 3969d4104b2SJohn Baldwin GElf_Phdr phdr; 3979d4104b2SJohn Baldwin bool dynamic, freebsd, pie; 3989d4104b2SJohn Baldwin int i; 399d3c1e14bSEdwin Groothuis 400d3c1e14bSEdwin Groothuis *is_shlib = 0; 401d3c1e14bSEdwin Groothuis *type = TYPE_UNKNOWN; 4029d4104b2SJohn Baldwin dynamic = false; 4039d4104b2SJohn Baldwin freebsd = false; 4049d4104b2SJohn Baldwin pie = false; 405d3c1e14bSEdwin Groothuis 4069d4104b2SJohn Baldwin if (elf_version(EV_CURRENT) == EV_NONE) { 4079d4104b2SJohn Baldwin warnx("unsupported libelf"); 408d3c1e14bSEdwin Groothuis return (0); 409d3c1e14bSEdwin Groothuis } 4109d4104b2SJohn Baldwin elf = elf_begin(fd, ELF_C_READ, NULL); 4119d4104b2SJohn Baldwin if (elf == NULL) { 4129d4104b2SJohn Baldwin warnx("%s: %s", fname, elf_errmsg(0)); 413fffd993dSEdwin Groothuis return (0); 414fffd993dSEdwin Groothuis } 4159d4104b2SJohn Baldwin if (elf_kind(elf) != ELF_K_ELF) { 4169d4104b2SJohn Baldwin elf_end(elf); 417fffd993dSEdwin Groothuis warnx("%s: not a dynamic ELF executable", fname); 418fffd993dSEdwin Groothuis return (0); 419fffd993dSEdwin Groothuis } 4209d4104b2SJohn Baldwin if (gelf_getehdr(elf, &ehdr) == NULL) { 4219d4104b2SJohn Baldwin warnx("%s: %s", fname, elf_errmsg(0)); 4229d4104b2SJohn Baldwin elf_end(elf); 423fffd993dSEdwin Groothuis return (0); 424fffd993dSEdwin Groothuis } 425fffd993dSEdwin Groothuis 426d3c1e14bSEdwin Groothuis *type = TYPE_ELF; 4279d4104b2SJohn Baldwin #if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED) 4289d4104b2SJohn Baldwin if (gelf_getclass(elf) == ELFCLASS32) { 4299d4104b2SJohn Baldwin *type = TYPE_ELF32; 4309d4104b2SJohn Baldwin } 4319d4104b2SJohn Baldwin #endif 432d3c1e14bSEdwin Groothuis 4339d4104b2SJohn Baldwin freebsd = ehdr.e_ident[EI_OSABI] == ELFOSABI_FREEBSD; 4349d4104b2SJohn Baldwin for (i = 0; i < ehdr.e_phnum; i++) { 4359d4104b2SJohn Baldwin if (gelf_getphdr(elf, i, &phdr) == NULL) { 4369d4104b2SJohn Baldwin warnx("%s: %s", fname, elf_errmsg(0)); 4379d4104b2SJohn Baldwin elf_end(elf); 438d3c1e14bSEdwin Groothuis return (0); 439d3c1e14bSEdwin Groothuis } 4409d4104b2SJohn Baldwin switch (phdr.p_type) { 4419d4104b2SJohn Baldwin case PT_NOTE: 4429d4104b2SJohn Baldwin if (ehdr.e_ident[EI_OSABI] == ELFOSABI_NONE && !freebsd) 4439d4104b2SJohn Baldwin freebsd = has_freebsd_abi_tag(fname, elf, &ehdr, 4449d4104b2SJohn Baldwin phdr.p_offset, phdr.p_filesz); 4459d4104b2SJohn Baldwin break; 4469d4104b2SJohn Baldwin case PT_DYNAMIC: 4479d4104b2SJohn Baldwin dynamic = true; 4489d4104b2SJohn Baldwin if (ehdr.e_type == ET_DYN) 4499d4104b2SJohn Baldwin pie = is_pie(fname, elf, &ehdr, phdr.p_offset, 4509d4104b2SJohn Baldwin phdr.p_filesz); 451d3c1e14bSEdwin Groothuis break; 452d3c1e14bSEdwin Groothuis } 453d3c1e14bSEdwin Groothuis } 454d3c1e14bSEdwin Groothuis 455d3c1e14bSEdwin Groothuis if (!dynamic) { 4569d4104b2SJohn Baldwin elf_end(elf); 457d3c1e14bSEdwin Groothuis warnx("%s: not a dynamic ELF executable", fname); 458d3c1e14bSEdwin Groothuis return (0); 459d3c1e14bSEdwin Groothuis } 4602b5d88fdSKonstantin Belousov 4619d4104b2SJohn Baldwin if (ehdr.e_type == ET_DYN && !pie) { 4629d4104b2SJohn Baldwin *is_shlib = 1; 4632b5d88fdSKonstantin Belousov 4649d4104b2SJohn Baldwin if (!freebsd) { 4659d4104b2SJohn Baldwin elf_end(elf); 466d3c1e14bSEdwin Groothuis warnx("%s: not a FreeBSD ELF shared object", fname); 467d3c1e14bSEdwin Groothuis return (0); 468d3c1e14bSEdwin Groothuis } 469d3c1e14bSEdwin Groothuis } 470d3c1e14bSEdwin Groothuis 4719d4104b2SJohn Baldwin elf_end(elf); 4729d4104b2SJohn Baldwin return (1); 473d3c1e14bSEdwin Groothuis } 474