1 /* $OpenBSD: ldd.c,v 1.19 2015/01/20 02:16:19 deraadt Exp $ */ 2 /* 3 * Copyright (c) 2001 Artur Grabowski <art@openbsd.org> 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. The name of the author may not be used to endorse or promote products 13 * derived from this software without specific prior written permission. 14 * 15 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 16 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 17 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 18 * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #include <stdio.h> 28 #include <stdlib.h> 29 #include <elf_abi.h> 30 #include <err.h> 31 #include <fcntl.h> 32 #include <string.h> 33 #include <signal.h> 34 #include <unistd.h> 35 #include <limits.h> 36 #include <dlfcn.h> 37 #include <errno.h> 38 39 #include <sys/stat.h> 40 #include <sys/mman.h> 41 #include <sys/wait.h> 42 43 int usage(void); 44 int doit(char *); 45 46 int 47 main(int argc, char **argv) 48 { 49 int c, xflag, ret; 50 51 xflag = 0; 52 while ((c = getopt(argc, argv, "x")) != -1) { 53 switch (c) { 54 case 'x': 55 xflag = 1; 56 break; 57 default: 58 usage(); 59 /*NOTREACHED*/ 60 } 61 } 62 63 if (xflag) 64 errx(1, "-x not yet implemented"); 65 66 argc -= optind; 67 argv += optind; 68 69 if (argc == 0) 70 usage(); 71 72 if (setenv("LD_TRACE_LOADED_OBJECTS", "true", 1) < 0) 73 err(1, "setenv(LD_TRACE_LOADED_OBJECTS)"); 74 75 ret = 0; 76 while (argc--) { 77 ret |= doit(*argv); 78 argv++; 79 } 80 81 return ret; 82 } 83 84 int 85 usage(void) 86 { 87 extern char *__progname; 88 89 fprintf(stderr, "usage: %s program ...\n", __progname); 90 exit(1); 91 } 92 93 94 int 95 doit(char *name) 96 { 97 Elf_Ehdr ehdr; 98 Elf_Phdr *phdr; 99 int fd, i, size, status, interp=0; 100 char buf[PATH_MAX]; 101 struct stat st; 102 void * dlhandle; 103 104 if ((fd = open(name, O_RDONLY)) < 0) { 105 warn("%s", name); 106 return 1; 107 } 108 109 if (fstat(fd, &st) == -1) { 110 warn("%s", name); 111 close(fd); 112 return 1; 113 } 114 115 if (!S_ISREG(st.st_mode)) { 116 warnx("%s: not an regular file", name); 117 close(fd); 118 return 1; 119 } 120 if (read(fd, &ehdr, sizeof(ehdr)) < 0) { 121 warn("read(%s)", name); 122 close(fd); 123 return 1; 124 } 125 126 if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) || 127 ehdr.e_machine != ELF_TARG_MACH) { 128 warnx("%s: not an ELF executable", name); 129 close(fd); 130 return 1; 131 } 132 133 if ((phdr = reallocarray(NULL, ehdr.e_phnum, sizeof(Elf_Phdr))) == NULL) 134 err(1, "reallocarray"); 135 size = ehdr.e_phnum * sizeof(Elf_Phdr); 136 137 if (pread(fd, phdr, size, ehdr.e_phoff) != size) { 138 warn("read(%s)", name); 139 close(fd); 140 free(phdr); 141 return 1; 142 } 143 close(fd); 144 145 for (i = 0; i < ehdr.e_phnum; i++) 146 if (phdr[i].p_type == PT_INTERP) { 147 interp = 1; 148 break; 149 } 150 free(phdr); 151 152 printf("%s:\n", name); 153 fflush(stdout); 154 switch (fork()) { 155 case -1: 156 err(1, "fork"); 157 case 0: 158 if (ehdr.e_type == ET_DYN && !interp) { 159 if (realpath(name, buf) == NULL) { 160 printf("realpath(%s): %s", name, 161 strerror(errno)); 162 fflush(stdout); 163 _exit(1); 164 } 165 dlhandle = dlopen(buf, RTLD_TRACE); 166 if (dlhandle == NULL) { 167 printf("%s\n", dlerror()); 168 fflush(stdout); 169 _exit(1); 170 } 171 _exit(0); 172 } 173 174 if (i == ehdr.e_phnum) { 175 printf("not a dynamic executable\n"); 176 fflush(stdout); 177 _exit(0); 178 } 179 180 execl(name, name, (char *)NULL); 181 perror(name); 182 _exit(1); 183 default: 184 if (wait(&status) < 0) { 185 warn("wait"); 186 return 1; 187 } 188 if (WIFSIGNALED(status)) { 189 if (WTERMSIG(status) == SIGINT) 190 return 1; 191 fprintf(stderr, "%s: signal %d\n", name, 192 WTERMSIG(status)); 193 return 1; 194 } 195 if (WEXITSTATUS(status)) { 196 fprintf(stderr, "%s: exit status %d\n", name, 197 WEXITSTATUS(status)); 198 return 1; 199 } 200 } 201 202 return 0; 203 } 204