ldd.c revision 180236
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: head/usr.bin/ldd/ldd.c 180236 2008-07-03 22:37:51Z edwin $"); 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 51static int is_executable(const char *fname, int fd, int *is_shlib, 52 int *type); 53static void usage(void); 54 55#define TYPE_UNKNOWN 0 56#define TYPE_AOUT 1 57#define TYPE_ELF 2 /* Architecture default */ 58#if __ELF_WORD_SIZE > 32 59#define TYPE_ELF32 3 /* Explicit 32 bits on architectures >32 bits */ 60#endif 61 62#define ENV_OBJECTS 0 63#define ENV_OBJECTS_FMT1 1 64#define ENV_OBJECTS_FMT2 2 65#define ENV_OBJECTS_PROGNAME 3 66#define ENV_OBJECTS_ALL 4 67#define ENV_LAST 5 68 69const char *envdef[ENV_LAST] = { 70 "LD_TRACE_LOADED_OBJECTS", 71 "LD_TRACE_LOADED_OBJECTS_FMT1", 72 "LD_TRACE_LOADED_OBJECTS_FMT2", 73 "LD_TRACE_LOADED_OBJECTS_PROGNAME", 74 "LD_TRACE_LOADED_OBJECTS_ALL", 75}; 76#if __ELF_WORD_SIZE > 32 77const char *env32[ENV_LAST] = { 78 "LD_32_TRACE_LOADED_OBJECTS", 79 "LD_32_TRACE_LOADED_OBJECTS_FMT1", 80 "LD_32_TRACE_LOADED_OBJECTS_FMT2", 81 "LD_32_TRACE_LOADED_OBJECTS_PROGNAME", 82 "LD_32_TRACE_LOADED_OBJECTS_ALL", 83}; 84#endif 85 86int 87main(int argc, char *argv[]) 88{ 89 char *fmt1, *fmt2; 90 int rval, c, aflag, vflag; 91 92 aflag = vflag = 0; 93 fmt1 = fmt2 = NULL; 94 95 while ((c = getopt(argc, argv, "af:v")) != -1) { 96 switch (c) { 97 case 'a': 98 aflag++; 99 break; 100 case 'f': 101 if (fmt1 != NULL) { 102 if (fmt2 != NULL) 103 errx(1, "too many formats"); 104 fmt2 = optarg; 105 } else 106 fmt1 = optarg; 107 break; 108 case 'v': 109 vflag++; 110 break; 111 default: 112 usage(); 113 /* NOTREACHED */ 114 } 115 } 116 argc -= optind; 117 argv += optind; 118 119 if (vflag && fmt1 != NULL) 120 errx(1, "-v may not be used with -f"); 121 122 if (argc <= 0) { 123 usage(); 124 /* NOTREACHED */ 125 } 126 127#ifdef __i386__ 128 if (vflag) { 129 for (c = 0; c < argc; c++) 130 dump_file(argv[c]); 131 exit(error_count == 0 ? EXIT_SUCCESS : EXIT_FAILURE); 132 } 133#endif 134 135 rval = 0; 136 for (; argc > 0; argc--, argv++) { 137 int fd, status, is_shlib, rv, type; 138 const char **env; 139 140 if ((fd = open(*argv, O_RDONLY, 0)) < 0) { 141 warn("%s", *argv); 142 rval |= 1; 143 continue; 144 } 145 rv = is_executable(*argv, fd, &is_shlib, &type); 146 close(fd); 147 if (rv == 0) { 148 rval |= 1; 149 continue; 150 } 151 152 switch (type) { 153 case TYPE_ELF: 154 case TYPE_AOUT: 155 env = envdef; 156 break; 157#if __ELF_WORD_SIZE > 32 158 case TYPE_ELF32: 159 env = env32; 160 break; 161#endif 162 case TYPE_UNKNOWN: 163 default: 164 /* 165 * This shouldn't happen unless is_executable() 166 * is broken. 167 */ 168 errx(EDOOFUS, "unknown executable type"); 169 } 170 171 /* ld.so magic */ 172 setenv(env[ENV_OBJECTS], "yes", 1); 173 if (fmt1 != NULL) 174 setenv(env[ENV_OBJECTS_FMT1], fmt1, 1); 175 if (fmt2 != NULL) 176 setenv(env[ENV_OBJECTS_FMT2], fmt2, 1); 177 178 setenv(env[ENV_OBJECTS_PROGNAME], *argv, 1); 179 if (aflag) 180 setenv(env[ENV_OBJECTS_ALL], "1", 1); 181 else if (fmt1 == NULL && fmt2 == NULL) 182 /* Default formats */ 183 printf("%s:\n", *argv); 184 fflush(stdout); 185 186 switch (fork()) { 187 case -1: 188 err(1, "fork"); 189 break; 190 default: 191 if (wait(&status) <= 0) { 192 warn("wait"); 193 rval |= 1; 194 } else if (WIFSIGNALED(status)) { 195 fprintf(stderr, "%s: signal %d\n", *argv, 196 WTERMSIG(status)); 197 rval |= 1; 198 } else if (WIFEXITED(status) && WEXITSTATUS(status)) { 199 fprintf(stderr, "%s: exit status %d\n", *argv, 200 WEXITSTATUS(status)); 201 rval |= 1; 202 } 203 break; 204 case 0: 205 if (is_shlib == 0) { 206 execl(*argv, *argv, (char *)NULL); 207 warn("%s", *argv); 208 } else { 209 dlopen(*argv, RTLD_TRACE); 210 warnx("%s: %s", *argv, dlerror()); 211 } 212 _exit(1); 213 } 214 } 215 216 return rval; 217} 218 219static void 220usage(void) 221{ 222 223 fprintf(stderr, "usage: ldd [-a] [-v] [-f format] program ...\n"); 224 exit(1); 225} 226 227static int 228is_executable(const char *fname, int fd, int *is_shlib, int *type) 229{ 230 union { 231 struct exec aout; 232 Elf32_Ehdr elf32; 233 Elf_Ehdr elf; 234 } hdr; 235 int n; 236 237 *is_shlib = 0; 238 *type = TYPE_UNKNOWN; 239 240 if ((n = read(fd, &hdr, sizeof(hdr))) == -1) { 241 warn("%s: can't read program header", fname); 242 return (0); 243 } 244 245 if ((size_t)n >= sizeof(hdr.aout) && !N_BADMAG(hdr.aout)) { 246 /* a.out file */ 247 if ((N_GETFLAG(hdr.aout) & EX_DPMASK) != EX_DYNAMIC 248#if 1 /* Compatibility */ 249 || hdr.aout.a_entry < __LDPGSZ 250#endif 251 ) { 252 warnx("%s: not a dynamic executable", fname); 253 return (0); 254 } 255 *type = TYPE_AOUT; 256 return (1); 257 } 258 259#if __ELF_WORD_SIZE > 32 260 if ((size_t)n >= sizeof(hdr.elf32) && IS_ELF(hdr.elf32) && 261 hdr.elf32.e_ident[EI_CLASS] == ELFCLASS32) { 262 /* Handle 32 bit ELF objects */ 263 Elf32_Phdr phdr; 264 int dynamic, i; 265 266 dynamic = 0; 267 *type = TYPE_ELF32; 268 269 if (lseek(fd, hdr.elf32.e_phoff, SEEK_SET) == -1) { 270 warnx("%s: header too short", fname); 271 return (0); 272 } 273 for (i = 0; i < hdr.elf32.e_phnum; i++) { 274 if (read(fd, &phdr, hdr.elf32.e_phentsize) != 275 sizeof(phdr)) { 276 warnx("%s: can't read program header", fname); 277 return (0); 278 } 279 if (phdr.p_type == PT_DYNAMIC) { 280 dynamic = 1; 281 break; 282 } 283 } 284 285 if (!dynamic) { 286 warnx("%s: not a dynamic ELF executable", fname); 287 return (0); 288 } 289 if (hdr.elf32.e_type == ET_DYN) { 290 if (hdr.elf32.e_ident[EI_OSABI] & ELFOSABI_FREEBSD) { 291 *is_shlib = 1; 292 return (1); 293 } 294 warnx("%s: not a FreeBSD ELF shared object", fname); 295 return (0); 296 } 297 298 return (1); 299 } 300#endif 301 302 if ((size_t)n >= sizeof(hdr.elf) && IS_ELF(hdr.elf) && 303 hdr.elf.e_ident[EI_CLASS] == ELF_TARG_CLASS) { 304 /* Handle default ELF objects on this architecture */ 305 Elf_Phdr phdr; 306 int dynamic, i; 307 308 dynamic = 0; 309 *type = TYPE_ELF; 310 311 if (lseek(fd, hdr.elf.e_phoff, SEEK_SET) == -1) { 312 warnx("%s: header too short", fname); 313 return (0); 314 } 315 for (i = 0; i < hdr.elf.e_phnum; i++) { 316 if (read(fd, &phdr, hdr.elf.e_phentsize) 317 != sizeof(phdr)) { 318 warnx("%s: can't read program header", fname); 319 return (0); 320 } 321 if (phdr.p_type == PT_DYNAMIC) { 322 dynamic = 1; 323 break; 324 } 325 } 326 327 if (!dynamic) { 328 warnx("%s: not a dynamic ELF executable", fname); 329 return (0); 330 } 331 if (hdr.elf.e_type == ET_DYN) { 332 if (hdr.elf.e_ident[EI_OSABI] & ELFOSABI_FREEBSD) { 333 *is_shlib = 1; 334 return (1); 335 } 336 warnx("%s: not a FreeBSD ELF shared object", fname); 337 return (0); 338 } 339 340 return (1); 341 } 342 343 warnx("%s: not a dynamic executable", fname); 344 return (0); 345} 346