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> 43699e1b82SRich Murphey #include <fcntl.h> 44699e1b82SRich Murphey #include <stdio.h> 45699e1b82SRich Murphey #include <stdlib.h> 46699e1b82SRich Murphey #include <unistd.h> 47b9ae52e3SPaul Richards 48a53809fdSMark Murray #include "extern.h" 499731d137SPeter Wemm 50d3c1e14bSEdwin Groothuis static int is_executable(const char *fname, int fd, int *is_shlib, 51d3c1e14bSEdwin Groothuis int *type); 52d3c1e14bSEdwin Groothuis static void usage(void); 53a0d476a9SEdwin Groothuis 54d3c1e14bSEdwin Groothuis #define TYPE_UNKNOWN 0 55d3c1e14bSEdwin Groothuis #define TYPE_AOUT 1 56d3c1e14bSEdwin Groothuis #define TYPE_ELF 2 /* Architecture default */ 57d3c1e14bSEdwin Groothuis 58d3c1e14bSEdwin Groothuis #define ENV_OBJECTS 0 59d3c1e14bSEdwin Groothuis #define ENV_OBJECTS_FMT1 1 60d3c1e14bSEdwin Groothuis #define ENV_OBJECTS_FMT2 2 61d3c1e14bSEdwin Groothuis #define ENV_OBJECTS_PROGNAME 3 62d3c1e14bSEdwin Groothuis #define ENV_OBJECTS_ALL 4 63d3c1e14bSEdwin Groothuis #define ENV_LAST 5 64d3c1e14bSEdwin Groothuis 65d3c1e14bSEdwin Groothuis const char *envdef[ENV_LAST] = { 66d3c1e14bSEdwin Groothuis "LD_TRACE_LOADED_OBJECTS", 67d3c1e14bSEdwin Groothuis "LD_TRACE_LOADED_OBJECTS_FMT1", 68d3c1e14bSEdwin Groothuis "LD_TRACE_LOADED_OBJECTS_FMT2", 69d3c1e14bSEdwin Groothuis "LD_TRACE_LOADED_OBJECTS_PROGNAME", 70d3c1e14bSEdwin Groothuis "LD_TRACE_LOADED_OBJECTS_ALL", 71d3c1e14bSEdwin Groothuis }; 72b9ae52e3SPaul Richards 73b9ae52e3SPaul Richards int 74a53809fdSMark Murray main(int argc, char *argv[]) 75b9ae52e3SPaul Richards { 76a0d476a9SEdwin Groothuis char *fmt1, *fmt2; 77a0d476a9SEdwin Groothuis int rval, c, aflag, vflag; 78b9ae52e3SPaul Richards 7920249943SDavid E. O'Brien aflag = vflag = 0; 80a0d476a9SEdwin Groothuis fmt1 = fmt2 = NULL; 8120249943SDavid E. O'Brien 82a0d476a9SEdwin Groothuis while ((c = getopt(argc, argv, "af:v")) != -1) { 83b9ae52e3SPaul Richards switch (c) { 8420249943SDavid E. O'Brien case 'a': 8520249943SDavid E. O'Brien aflag++; 8620249943SDavid E. O'Brien break; 87d138df61SPeter Wemm case 'f': 88a0d476a9SEdwin Groothuis if (fmt1 != NULL) { 89a0d476a9SEdwin Groothuis if (fmt2 != NULL) 903e762626SPhilippe Charnier errx(1, "too many formats"); 91d138df61SPeter Wemm fmt2 = optarg; 92d138df61SPeter Wemm } else 93d138df61SPeter Wemm fmt1 = optarg; 94d138df61SPeter Wemm break; 95a0d476a9SEdwin Groothuis case 'v': 96a0d476a9SEdwin Groothuis vflag++; 97a0d476a9SEdwin Groothuis break; 98b9ae52e3SPaul Richards default: 99b9ae52e3SPaul Richards usage(); 100699e1b82SRich Murphey /* NOTREACHED */ 101b9ae52e3SPaul Richards } 102b9ae52e3SPaul Richards } 103b9ae52e3SPaul Richards argc -= optind; 104b9ae52e3SPaul Richards argv += optind; 105b9ae52e3SPaul Richards 106a0d476a9SEdwin Groothuis if (vflag && fmt1 != NULL) 1079731d137SPeter Wemm errx(1, "-v may not be used with -f"); 1089731d137SPeter Wemm 109b9ae52e3SPaul Richards if (argc <= 0) { 110b9ae52e3SPaul Richards usage(); 111699e1b82SRich Murphey /* NOTREACHED */ 112b9ae52e3SPaul Richards } 113b9ae52e3SPaul Richards 11497db68b6SDoug Rabson #ifdef __i386__ 1159731d137SPeter Wemm if (vflag) { 1169731d137SPeter Wemm for (c = 0; c < argc; c++) 1179731d137SPeter Wemm dump_file(argv[c]); 1189731d137SPeter Wemm exit(error_count == 0 ? EXIT_SUCCESS : EXIT_FAILURE); 1199731d137SPeter Wemm } 12097db68b6SDoug Rabson #endif 1219731d137SPeter Wemm 122699e1b82SRich Murphey rval = 0; 123e2daa140SJohn Polstra for (; argc > 0; argc--, argv++) { 124d3c1e14bSEdwin Groothuis int fd, status, is_shlib, rv, type; 125d3c1e14bSEdwin Groothuis const char **env; 126d3c1e14bSEdwin Groothuis 127d3c1e14bSEdwin Groothuis env = envdef; /* Temporary placeholder */ 128b9ae52e3SPaul Richards 129b9ae52e3SPaul Richards if ((fd = open(*argv, O_RDONLY, 0)) < 0) { 130699e1b82SRich Murphey warn("%s", *argv); 131b9ae52e3SPaul Richards rval |= 1; 132b9ae52e3SPaul Richards continue; 133b9ae52e3SPaul Richards } 134d3c1e14bSEdwin Groothuis rv = is_executable(*argv, fd, &is_shlib, &type); 135a0d476a9SEdwin Groothuis close(fd); 136d3c1e14bSEdwin Groothuis if (rv == 0) { 137c474c6d3SDoug Rabson rval |= 1; 138c474c6d3SDoug Rabson continue; 139c474c6d3SDoug Rabson } 140c474c6d3SDoug Rabson 141d3c1e14bSEdwin Groothuis /* ld.so magic */ 142d3c1e14bSEdwin Groothuis setenv(env[ENV_OBJECTS], "yes", 1); 143d3c1e14bSEdwin Groothuis if (fmt1 != NULL) 144d3c1e14bSEdwin Groothuis setenv(env[ENV_OBJECTS_FMT1], fmt1, 1); 145d3c1e14bSEdwin Groothuis if (fmt2 != NULL) 146d3c1e14bSEdwin Groothuis setenv(env[ENV_OBJECTS_FMT2], fmt2, 1); 147a0d476a9SEdwin Groothuis 148d3c1e14bSEdwin Groothuis setenv(env[ENV_OBJECTS_PROGNAME], *argv, 1); 149a0d476a9SEdwin Groothuis if (aflag) 150d3c1e14bSEdwin Groothuis setenv(env[ENV_OBJECTS_ALL], "1", 1); 15120249943SDavid E. O'Brien else if (fmt1 == NULL && fmt2 == NULL) 152d138df61SPeter Wemm /* Default formats */ 153b9ae52e3SPaul Richards printf("%s:\n", *argv); 15409e3d49dSJordan K. Hubbard fflush(stdout); 155b9ae52e3SPaul Richards 156b9ae52e3SPaul Richards switch (fork()) { 157b9ae52e3SPaul Richards case -1: 158699e1b82SRich Murphey err(1, "fork"); 159b9ae52e3SPaul Richards break; 160b9ae52e3SPaul Richards default: 161699e1b82SRich Murphey if (wait(&status) <= 0) { 162699e1b82SRich Murphey warn("wait"); 163699e1b82SRich Murphey rval |= 1; 164699e1b82SRich Murphey } else if (WIFSIGNALED(status)) { 165a0d476a9SEdwin Groothuis fprintf(stderr, "%s: signal %d\n", *argv, 166a0d476a9SEdwin Groothuis WTERMSIG(status)); 167b9ae52e3SPaul Richards rval |= 1; 168b9ae52e3SPaul Richards } else if (WIFEXITED(status) && WEXITSTATUS(status)) { 169a0d476a9SEdwin Groothuis fprintf(stderr, "%s: exit status %d\n", *argv, 170a0d476a9SEdwin Groothuis WEXITSTATUS(status)); 171b9ae52e3SPaul Richards rval |= 1; 172b9ae52e3SPaul Richards } 173b9ae52e3SPaul Richards break; 174b9ae52e3SPaul Richards case 0: 175d1cf9ea2SMaxim Sobolev if (is_shlib == 0) { 176fc41545eSMaxim Sobolev execl(*argv, *argv, (char *)NULL); 1773e762626SPhilippe Charnier warn("%s", *argv); 178d1cf9ea2SMaxim Sobolev } else { 179d1cf9ea2SMaxim Sobolev dlopen(*argv, RTLD_TRACE); 180d1cf9ea2SMaxim Sobolev warnx("%s: %s", *argv, dlerror()); 181c6de4ce7SMaxim Sobolev } 182b9ae52e3SPaul Richards _exit(1); 183b9ae52e3SPaul Richards } 184b9ae52e3SPaul Richards } 185b9ae52e3SPaul Richards 186b9ae52e3SPaul Richards return rval; 187b9ae52e3SPaul Richards } 188d3c1e14bSEdwin Groothuis 189d3c1e14bSEdwin Groothuis static void 190d3c1e14bSEdwin Groothuis usage(void) 191d3c1e14bSEdwin Groothuis { 192d3c1e14bSEdwin Groothuis 193d3c1e14bSEdwin Groothuis fprintf(stderr, "usage: ldd [-a] [-v] [-f format] program ...\n"); 194d3c1e14bSEdwin Groothuis exit(1); 195d3c1e14bSEdwin Groothuis } 196d3c1e14bSEdwin Groothuis 197d3c1e14bSEdwin Groothuis static int 198d3c1e14bSEdwin Groothuis is_executable(const char *fname, int fd, int *is_shlib, int *type) 199d3c1e14bSEdwin Groothuis { 200d3c1e14bSEdwin Groothuis union { 201d3c1e14bSEdwin Groothuis struct exec aout; 202d3c1e14bSEdwin Groothuis Elf_Ehdr elf; 203d3c1e14bSEdwin Groothuis } hdr; 204d3c1e14bSEdwin Groothuis int n; 205d3c1e14bSEdwin Groothuis 206d3c1e14bSEdwin Groothuis *is_shlib = 0; 207d3c1e14bSEdwin Groothuis *type = TYPE_UNKNOWN; 208d3c1e14bSEdwin Groothuis 209d3c1e14bSEdwin Groothuis if ((n = read(fd, &hdr, sizeof(hdr))) == -1) { 210d3c1e14bSEdwin Groothuis warn("%s: can't read program header", fname); 211d3c1e14bSEdwin Groothuis return (0); 212d3c1e14bSEdwin Groothuis } 213d3c1e14bSEdwin Groothuis 214d3c1e14bSEdwin Groothuis if ((size_t)n >= sizeof(hdr.aout) && !N_BADMAG(hdr.aout)) { 215d3c1e14bSEdwin Groothuis /* a.out file */ 216d3c1e14bSEdwin Groothuis if ((N_GETFLAG(hdr.aout) & EX_DPMASK) != EX_DYNAMIC 217d3c1e14bSEdwin Groothuis #if 1 /* Compatibility */ 218d3c1e14bSEdwin Groothuis || hdr.aout.a_entry < __LDPGSZ 219d3c1e14bSEdwin Groothuis #endif 220d3c1e14bSEdwin Groothuis ) { 221d3c1e14bSEdwin Groothuis warnx("%s: not a dynamic executable", fname); 222d3c1e14bSEdwin Groothuis return (0); 223d3c1e14bSEdwin Groothuis } 224d3c1e14bSEdwin Groothuis *type = TYPE_AOUT; 225d3c1e14bSEdwin Groothuis return (1); 226d3c1e14bSEdwin Groothuis } 227d3c1e14bSEdwin Groothuis 228d3c1e14bSEdwin Groothuis if ((size_t)n >= sizeof(hdr.elf) && IS_ELF(hdr.elf) && 229d3c1e14bSEdwin Groothuis hdr.elf.e_ident[EI_CLASS] == ELF_TARG_CLASS) { 230d3c1e14bSEdwin Groothuis /* Handle default ELF objects on this architecture */ 231d3c1e14bSEdwin Groothuis Elf_Phdr phdr; 232d3c1e14bSEdwin Groothuis int dynamic, i; 233d3c1e14bSEdwin Groothuis 234d3c1e14bSEdwin Groothuis dynamic = 0; 235d3c1e14bSEdwin Groothuis *type = TYPE_ELF; 236d3c1e14bSEdwin Groothuis 237d3c1e14bSEdwin Groothuis if (lseek(fd, hdr.elf.e_phoff, SEEK_SET) == -1) { 238d3c1e14bSEdwin Groothuis warnx("%s: header too short", fname); 239d3c1e14bSEdwin Groothuis return (0); 240d3c1e14bSEdwin Groothuis } 241d3c1e14bSEdwin Groothuis for (i = 0; i < hdr.elf.e_phnum; i++) { 242d3c1e14bSEdwin Groothuis if (read(fd, &phdr, hdr.elf.e_phentsize) 243d3c1e14bSEdwin Groothuis != sizeof(phdr)) { 244d3c1e14bSEdwin Groothuis warnx("%s: can't read program header", fname); 245d3c1e14bSEdwin Groothuis return (0); 246d3c1e14bSEdwin Groothuis } 247d3c1e14bSEdwin Groothuis if (phdr.p_type == PT_DYNAMIC) { 248d3c1e14bSEdwin Groothuis dynamic = 1; 249d3c1e14bSEdwin Groothuis break; 250d3c1e14bSEdwin Groothuis } 251d3c1e14bSEdwin Groothuis } 252d3c1e14bSEdwin Groothuis 253d3c1e14bSEdwin Groothuis if (!dynamic) { 254d3c1e14bSEdwin Groothuis warnx("%s: not a dynamic ELF executable", fname); 255d3c1e14bSEdwin Groothuis return (0); 256d3c1e14bSEdwin Groothuis } 257d3c1e14bSEdwin Groothuis if (hdr.elf.e_type == ET_DYN) { 258d3c1e14bSEdwin Groothuis if (hdr.elf.e_ident[EI_OSABI] & ELFOSABI_FREEBSD) { 259d3c1e14bSEdwin Groothuis *is_shlib = 1; 260d3c1e14bSEdwin Groothuis return (1); 261d3c1e14bSEdwin Groothuis } 262d3c1e14bSEdwin Groothuis warnx("%s: not a FreeBSD ELF shared object", fname); 263d3c1e14bSEdwin Groothuis return (0); 264d3c1e14bSEdwin Groothuis } 265d3c1e14bSEdwin Groothuis 266d3c1e14bSEdwin Groothuis return (1); 267d3c1e14bSEdwin Groothuis } 268d3c1e14bSEdwin Groothuis 269d3c1e14bSEdwin Groothuis warnx("%s: not a dynamic executable", fname); 270d3c1e14bSEdwin Groothuis return (0); 271d3c1e14bSEdwin Groothuis } 272