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 <string.h> 48 #include <unistd.h> 49 50 #include "extern.h" 51 52 /* 53 * 32-bit ELF data structures can only be used if the system header[s] declare 54 * them. There is no official macro for determining whether they are declared, 55 * so check for the existence of one of the 32-macros defined in elf(5). 56 */ 57 #ifdef ELF32_R_TYPE 58 #define ELF32_SUPPORTED 59 #endif 60 61 #define LDD_SETENV(name, value, overwrite) do { \ 62 setenv("LD_" name, value, overwrite); \ 63 setenv("LD_32_" name, value, overwrite); \ 64 } while (0) 65 66 #define LDD_UNSETENV(name) do { \ 67 unsetenv("LD_" name); \ 68 unsetenv("LD_32_" name); \ 69 } while (0) 70 71 static int is_executable(const char *fname, int fd, int *is_shlib, 72 int *type); 73 static void usage(void); 74 75 #define TYPE_UNKNOWN 0 76 #define TYPE_AOUT 1 77 #define TYPE_ELF 2 /* Architecture default */ 78 #if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED) 79 #define TYPE_ELF32 3 /* Explicit 32 bits on architectures >32 bits */ 80 81 #define _PATH_LDD32 "/usr/bin/ldd32" 82 83 static int 84 execldd32(char *file, char *fmt1, char *fmt2, int aflag, int vflag) 85 { 86 char *argv[8]; 87 int i, rval, status; 88 89 LDD_UNSETENV("TRACE_LOADED_OBJECTS"); 90 rval = 0; 91 i = 0; 92 argv[i++] = strdup(_PATH_LDD32); 93 if (aflag) 94 argv[i++] = strdup("-a"); 95 if (vflag) 96 argv[i++] = strdup("-v"); 97 if (fmt1 != NULL) { 98 argv[i++] = strdup("-f"); 99 argv[i++] = strdup(fmt1); 100 } 101 if (fmt2 != NULL) { 102 argv[i++] = strdup("-f"); 103 argv[i++] = strdup(fmt2); 104 } 105 argv[i++] = strdup(file); 106 argv[i++] = NULL; 107 108 switch (fork()) { 109 case -1: 110 err(1, "fork"); 111 break; 112 case 0: 113 execv(_PATH_LDD32, argv); 114 warn("%s", _PATH_LDD32); 115 _exit(127); 116 break; 117 default: 118 if (wait(&status) < 0) 119 rval = 1; 120 else if (WIFSIGNALED(status)) 121 rval = 1; 122 else if (WIFEXITED(status) && WEXITSTATUS(status) != 0) 123 rval = 1; 124 break; 125 } 126 while (i--) 127 free(argv[i]); 128 LDD_SETENV("TRACE_LOADED_OBJECTS", "yes", 1); 129 return (rval); 130 } 131 #endif 132 133 int 134 main(int argc, char *argv[]) 135 { 136 char *fmt1, *fmt2; 137 int rval, c, aflag, vflag; 138 139 aflag = vflag = 0; 140 fmt1 = fmt2 = NULL; 141 142 while ((c = getopt(argc, argv, "af:v")) != -1) { 143 switch (c) { 144 case 'a': 145 aflag++; 146 break; 147 case 'f': 148 if (fmt1 != NULL) { 149 if (fmt2 != NULL) 150 errx(1, "too many formats"); 151 fmt2 = optarg; 152 } else 153 fmt1 = optarg; 154 break; 155 case 'v': 156 vflag++; 157 break; 158 default: 159 usage(); 160 /* NOTREACHED */ 161 } 162 } 163 argc -= optind; 164 argv += optind; 165 166 if (vflag && fmt1 != NULL) 167 errx(1, "-v may not be used with -f"); 168 169 if (argc <= 0) { 170 usage(); 171 /* NOTREACHED */ 172 } 173 174 #ifdef __i386__ 175 if (vflag) { 176 for (c = 0; c < argc; c++) 177 dump_file(argv[c]); 178 exit(error_count == 0 ? EXIT_SUCCESS : EXIT_FAILURE); 179 } 180 #endif 181 182 rval = 0; 183 for (; argc > 0; argc--, argv++) { 184 int fd, status, is_shlib, rv, type; 185 186 if ((fd = open(*argv, O_RDONLY, 0)) < 0) { 187 warn("%s", *argv); 188 rval |= 1; 189 continue; 190 } 191 rv = is_executable(*argv, fd, &is_shlib, &type); 192 close(fd); 193 if (rv == 0) { 194 rval |= 1; 195 continue; 196 } 197 198 switch (type) { 199 case TYPE_ELF: 200 case TYPE_AOUT: 201 break; 202 #if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED) 203 case TYPE_ELF32: 204 rval |= execldd32(*argv, fmt1, fmt2, aflag, vflag); 205 continue; 206 #endif 207 case TYPE_UNKNOWN: 208 default: 209 /* 210 * This shouldn't happen unless is_executable() 211 * is broken. 212 */ 213 errx(EDOOFUS, "unknown executable type"); 214 } 215 216 /* ld.so magic */ 217 LDD_SETENV("TRACE_LOADED_OBJECTS", "yes", 1); 218 if (fmt1 != NULL) 219 LDD_SETENV("TRACE_LOADED_OBJECTS_FMT1", fmt1, 1); 220 if (fmt2 != NULL) 221 LDD_SETENV("TRACE_LOADED_OBJECTS_FMT2", fmt2, 1); 222 223 LDD_SETENV("TRACE_LOADED_OBJECTS_PROGNAME", *argv, 1); 224 if (aflag) 225 LDD_SETENV("TRACE_LOADED_OBJECTS_ALL", "1", 1); 226 else if (fmt1 == NULL && fmt2 == NULL) 227 /* Default formats */ 228 printf("%s:\n", *argv); 229 fflush(stdout); 230 231 switch (fork()) { 232 case -1: 233 err(1, "fork"); 234 break; 235 default: 236 if (wait(&status) < 0) { 237 warn("wait"); 238 rval |= 1; 239 } else if (WIFSIGNALED(status)) { 240 fprintf(stderr, "%s: signal %d\n", *argv, 241 WTERMSIG(status)); 242 rval |= 1; 243 } else if (WIFEXITED(status) && 244 WEXITSTATUS(status) != 0) { 245 fprintf(stderr, "%s: exit status %d\n", *argv, 246 WEXITSTATUS(status)); 247 rval |= 1; 248 } 249 break; 250 case 0: 251 if (is_shlib == 0) { 252 execl(*argv, *argv, (char *)NULL); 253 warn("%s", *argv); 254 } else { 255 dlopen(*argv, RTLD_TRACE); 256 warnx("%s: %s", *argv, dlerror()); 257 } 258 _exit(1); 259 } 260 } 261 262 return rval; 263 } 264 265 static void 266 usage(void) 267 { 268 269 fprintf(stderr, "usage: ldd [-a] [-v] [-f format] program ...\n"); 270 exit(1); 271 } 272 273 static int 274 is_executable(const char *fname, int fd, int *is_shlib, int *type) 275 { 276 union { 277 struct exec aout; 278 #if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED) 279 Elf32_Ehdr elf32; 280 #endif 281 Elf_Ehdr elf; 282 } hdr; 283 int n; 284 285 *is_shlib = 0; 286 *type = TYPE_UNKNOWN; 287 288 if ((n = read(fd, &hdr, sizeof(hdr))) == -1) { 289 warn("%s: can't read program header", fname); 290 return (0); 291 } 292 293 if ((size_t)n >= sizeof(hdr.aout) && !N_BADMAG(hdr.aout)) { 294 /* a.out file */ 295 if ((N_GETFLAG(hdr.aout) & EX_DPMASK) != EX_DYNAMIC 296 #if 1 /* Compatibility */ 297 || hdr.aout.a_entry < __LDPGSZ 298 #endif 299 ) { 300 warnx("%s: not a dynamic executable", fname); 301 return (0); 302 } 303 *type = TYPE_AOUT; 304 return (1); 305 } 306 307 #if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED) 308 if ((size_t)n >= sizeof(hdr.elf32) && IS_ELF(hdr.elf32) && 309 hdr.elf32.e_ident[EI_CLASS] == ELFCLASS32) { 310 /* Handle 32 bit ELF objects */ 311 Elf32_Phdr phdr; 312 int dynamic, i; 313 314 dynamic = 0; 315 *type = TYPE_ELF32; 316 317 if (lseek(fd, hdr.elf32.e_phoff, SEEK_SET) == -1) { 318 warnx("%s: header too short", fname); 319 return (0); 320 } 321 for (i = 0; i < hdr.elf32.e_phnum; i++) { 322 if (read(fd, &phdr, hdr.elf32.e_phentsize) != 323 sizeof(phdr)) { 324 warnx("%s: can't read program header", fname); 325 return (0); 326 } 327 if (phdr.p_type == PT_DYNAMIC) { 328 dynamic = 1; 329 break; 330 } 331 } 332 333 if (!dynamic) { 334 warnx("%s: not a dynamic ELF executable", fname); 335 return (0); 336 } 337 if (hdr.elf32.e_type == ET_DYN) { 338 if (hdr.elf32.e_ident[EI_OSABI] == ELFOSABI_FREEBSD) { 339 *is_shlib = 1; 340 return (1); 341 } 342 warnx("%s: not a FreeBSD ELF shared object", fname); 343 return (0); 344 } 345 346 return (1); 347 } 348 #endif 349 350 if ((size_t)n >= sizeof(hdr.elf) && IS_ELF(hdr.elf) && 351 hdr.elf.e_ident[EI_CLASS] == ELF_TARG_CLASS) { 352 /* Handle default ELF objects on this architecture */ 353 Elf_Phdr phdr; 354 int dynamic, i; 355 356 dynamic = 0; 357 *type = TYPE_ELF; 358 359 if (lseek(fd, hdr.elf.e_phoff, SEEK_SET) == -1) { 360 warnx("%s: header too short", fname); 361 return (0); 362 } 363 for (i = 0; i < hdr.elf.e_phnum; i++) { 364 if (read(fd, &phdr, hdr.elf.e_phentsize) 365 != sizeof(phdr)) { 366 warnx("%s: can't read program header", fname); 367 return (0); 368 } 369 if (phdr.p_type == PT_DYNAMIC) { 370 dynamic = 1; 371 break; 372 } 373 } 374 375 if (!dynamic) { 376 warnx("%s: not a dynamic ELF executable", fname); 377 return (0); 378 } 379 if (hdr.elf.e_type == ET_DYN) { 380 if (hdr.elf.e_ident[EI_OSABI] == ELFOSABI_FREEBSD) { 381 *is_shlib = 1; 382 return (1); 383 } 384 warnx("%s: not a FreeBSD ELF shared object", fname); 385 return (0); 386 } 387 388 return (1); 389 } 390 391 warnx("%s: not a dynamic executable", fname); 392 return (0); 393 } 394