1 /* 2 * Copyright (c) 1993 Paul Kranenburg 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by Paul Kranenburg. 16 * 4. The name of the author may not be used to endorse or promote products 17 * derived from this software without specific prior written permission 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include <sys/cdefs.h> 32 __FBSDID("$FreeBSD$"); 33 34 #include <sys/wait.h> 35 36 #include <machine/elf.h> 37 38 #include <arpa/inet.h> 39 40 #include <a.out.h> 41 #include <dlfcn.h> 42 #include <err.h> 43 #include <errno.h> 44 #include <fcntl.h> 45 #include <stdio.h> 46 #include <stdlib.h> 47 #include <unistd.h> 48 49 #include "extern.h" 50 51 /* 52 * 32-bit ELF data structures can only be used if the system header[s] declare 53 * them. There is no official macro for determining whether they are declared, 54 * so check for the existence of one of the 32-macros defined in elf(5). 55 */ 56 #ifdef ELF32_R_TYPE 57 #define ELF32_SUPPORTED 58 #endif 59 60 static int is_executable(const char *fname, int fd, int *is_shlib, 61 int *type); 62 static void usage(void); 63 64 #define TYPE_UNKNOWN 0 65 #define TYPE_AOUT 1 66 #define TYPE_ELF 2 /* Architecture default */ 67 #if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED) 68 #define TYPE_ELF32 3 /* Explicit 32 bits on architectures >32 bits */ 69 #endif 70 71 #define ENV_OBJECTS 0 72 #define ENV_OBJECTS_FMT1 1 73 #define ENV_OBJECTS_FMT2 2 74 #define ENV_OBJECTS_PROGNAME 3 75 #define ENV_OBJECTS_ALL 4 76 #define ENV_LAST 5 77 78 const char *envdef[ENV_LAST] = { 79 "LD_TRACE_LOADED_OBJECTS", 80 "LD_TRACE_LOADED_OBJECTS_FMT1", 81 "LD_TRACE_LOADED_OBJECTS_FMT2", 82 "LD_TRACE_LOADED_OBJECTS_PROGNAME", 83 "LD_TRACE_LOADED_OBJECTS_ALL", 84 }; 85 #if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED) 86 const char *env32[ENV_LAST] = { 87 "LD_32_TRACE_LOADED_OBJECTS", 88 "LD_32_TRACE_LOADED_OBJECTS_FMT1", 89 "LD_32_TRACE_LOADED_OBJECTS_FMT2", 90 "LD_32_TRACE_LOADED_OBJECTS_PROGNAME", 91 "LD_32_TRACE_LOADED_OBJECTS_ALL", 92 }; 93 #endif 94 95 int 96 main(int argc, char *argv[]) 97 { 98 char *fmt1, *fmt2; 99 int rval, c, aflag, vflag; 100 101 aflag = vflag = 0; 102 fmt1 = fmt2 = NULL; 103 104 while ((c = getopt(argc, argv, "af:v")) != -1) { 105 switch (c) { 106 case 'a': 107 aflag++; 108 break; 109 case 'f': 110 if (fmt1 != NULL) { 111 if (fmt2 != NULL) 112 errx(1, "too many formats"); 113 fmt2 = optarg; 114 } else 115 fmt1 = optarg; 116 break; 117 case 'v': 118 vflag++; 119 break; 120 default: 121 usage(); 122 /* NOTREACHED */ 123 } 124 } 125 argc -= optind; 126 argv += optind; 127 128 if (vflag && fmt1 != NULL) 129 errx(1, "-v may not be used with -f"); 130 131 if (argc <= 0) { 132 usage(); 133 /* NOTREACHED */ 134 } 135 136 #ifdef __i386__ 137 if (vflag) { 138 for (c = 0; c < argc; c++) 139 dump_file(argv[c]); 140 exit(error_count == 0 ? EXIT_SUCCESS : EXIT_FAILURE); 141 } 142 #endif 143 144 rval = 0; 145 for (; argc > 0; argc--, argv++) { 146 int fd, status, is_shlib, rv, type; 147 const char **env; 148 149 if ((fd = open(*argv, O_RDONLY, 0)) < 0) { 150 warn("%s", *argv); 151 rval |= 1; 152 continue; 153 } 154 rv = is_executable(*argv, fd, &is_shlib, &type); 155 close(fd); 156 if (rv == 0) { 157 rval |= 1; 158 continue; 159 } 160 161 switch (type) { 162 case TYPE_ELF: 163 case TYPE_AOUT: 164 env = envdef; 165 break; 166 #if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED) 167 case TYPE_ELF32: 168 env = env32; 169 break; 170 #endif 171 case TYPE_UNKNOWN: 172 default: 173 /* 174 * This shouldn't happen unless is_executable() 175 * is broken. 176 */ 177 errx(EDOOFUS, "unknown executable type"); 178 } 179 180 /* ld.so magic */ 181 setenv(env[ENV_OBJECTS], "yes", 1); 182 if (fmt1 != NULL) 183 setenv(env[ENV_OBJECTS_FMT1], fmt1, 1); 184 if (fmt2 != NULL) 185 setenv(env[ENV_OBJECTS_FMT2], fmt2, 1); 186 187 setenv(env[ENV_OBJECTS_PROGNAME], *argv, 1); 188 if (aflag) 189 setenv(env[ENV_OBJECTS_ALL], "1", 1); 190 else if (fmt1 == NULL && fmt2 == NULL) 191 /* Default formats */ 192 printf("%s:\n", *argv); 193 fflush(stdout); 194 195 switch (fork()) { 196 case -1: 197 err(1, "fork"); 198 break; 199 default: 200 if (wait(&status) <= 0) { 201 warn("wait"); 202 rval |= 1; 203 } else if (WIFSIGNALED(status)) { 204 fprintf(stderr, "%s: signal %d\n", *argv, 205 WTERMSIG(status)); 206 rval |= 1; 207 } else if (WIFEXITED(status) && WEXITSTATUS(status)) { 208 fprintf(stderr, "%s: exit status %d\n", *argv, 209 WEXITSTATUS(status)); 210 rval |= 1; 211 } 212 break; 213 case 0: 214 if (is_shlib == 0) { 215 execl(*argv, *argv, (char *)NULL); 216 warn("%s", *argv); 217 } else { 218 dlopen(*argv, RTLD_TRACE); 219 warnx("%s: %s", *argv, dlerror()); 220 } 221 _exit(1); 222 } 223 } 224 225 return rval; 226 } 227 228 static void 229 usage(void) 230 { 231 232 fprintf(stderr, "usage: ldd [-a] [-v] [-f format] program ...\n"); 233 exit(1); 234 } 235 236 static int 237 is_executable(const char *fname, int fd, int *is_shlib, int *type) 238 { 239 union { 240 struct exec aout; 241 #if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED) 242 Elf32_Ehdr elf32; 243 #endif 244 Elf_Ehdr elf; 245 } hdr; 246 int n; 247 248 *is_shlib = 0; 249 *type = TYPE_UNKNOWN; 250 251 if ((n = read(fd, &hdr, sizeof(hdr))) == -1) { 252 warn("%s: can't read program header", fname); 253 return (0); 254 } 255 256 if ((size_t)n >= sizeof(hdr.aout) && !N_BADMAG(hdr.aout)) { 257 /* a.out file */ 258 if ((N_GETFLAG(hdr.aout) & EX_DPMASK) != EX_DYNAMIC 259 #if 1 /* Compatibility */ 260 || hdr.aout.a_entry < __LDPGSZ 261 #endif 262 ) { 263 warnx("%s: not a dynamic executable", fname); 264 return (0); 265 } 266 *type = TYPE_AOUT; 267 return (1); 268 } 269 270 #if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED) 271 if ((size_t)n >= sizeof(hdr.elf32) && IS_ELF(hdr.elf32) && 272 hdr.elf32.e_ident[EI_CLASS] == ELFCLASS32) { 273 /* Handle 32 bit ELF objects */ 274 Elf32_Phdr phdr; 275 int dynamic, i; 276 277 dynamic = 0; 278 *type = TYPE_ELF32; 279 280 if (lseek(fd, hdr.elf32.e_phoff, SEEK_SET) == -1) { 281 warnx("%s: header too short", fname); 282 return (0); 283 } 284 for (i = 0; i < hdr.elf32.e_phnum; i++) { 285 if (read(fd, &phdr, hdr.elf32.e_phentsize) != 286 sizeof(phdr)) { 287 warnx("%s: can't read program header", fname); 288 return (0); 289 } 290 if (phdr.p_type == PT_DYNAMIC) { 291 dynamic = 1; 292 break; 293 } 294 } 295 296 if (!dynamic) { 297 warnx("%s: not a dynamic ELF executable", fname); 298 return (0); 299 } 300 if (hdr.elf32.e_type == ET_DYN) { 301 if (hdr.elf32.e_ident[EI_OSABI] & ELFOSABI_FREEBSD) { 302 *is_shlib = 1; 303 return (1); 304 } 305 warnx("%s: not a FreeBSD ELF shared object", fname); 306 return (0); 307 } 308 309 return (1); 310 } 311 #endif 312 313 if ((size_t)n >= sizeof(hdr.elf) && IS_ELF(hdr.elf) && 314 hdr.elf.e_ident[EI_CLASS] == ELF_TARG_CLASS) { 315 /* Handle default ELF objects on this architecture */ 316 Elf_Phdr phdr; 317 int dynamic, i; 318 319 dynamic = 0; 320 *type = TYPE_ELF; 321 322 if (lseek(fd, hdr.elf.e_phoff, SEEK_SET) == -1) { 323 warnx("%s: header too short", fname); 324 return (0); 325 } 326 for (i = 0; i < hdr.elf.e_phnum; i++) { 327 if (read(fd, &phdr, hdr.elf.e_phentsize) 328 != sizeof(phdr)) { 329 warnx("%s: can't read program header", fname); 330 return (0); 331 } 332 if (phdr.p_type == PT_DYNAMIC) { 333 dynamic = 1; 334 break; 335 } 336 } 337 338 if (!dynamic) { 339 warnx("%s: not a dynamic ELF executable", fname); 340 return (0); 341 } 342 if (hdr.elf.e_type == ET_DYN) { 343 if (hdr.elf.e_ident[EI_OSABI] & ELFOSABI_FREEBSD) { 344 *is_shlib = 1; 345 return (1); 346 } 347 warnx("%s: not a FreeBSD ELF shared object", fname); 348 return (0); 349 } 350 351 return (1); 352 } 353 354 warnx("%s: not a dynamic executable", fname); 355 return (0); 356 } 357