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