ldd.c revision 180235
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 180235 2008-07-03 22:30:18Z 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 <fcntl.h> 44#include <stdio.h> 45#include <stdlib.h> 46#include <unistd.h> 47 48#include "extern.h" 49 50static int is_executable(const char *fname, int fd, int *is_shlib, 51 int *type); 52static void usage(void); 53 54#define TYPE_UNKNOWN 0 55#define TYPE_AOUT 1 56#define TYPE_ELF 2 /* Architecture default */ 57 58#define ENV_OBJECTS 0 59#define ENV_OBJECTS_FMT1 1 60#define ENV_OBJECTS_FMT2 2 61#define ENV_OBJECTS_PROGNAME 3 62#define ENV_OBJECTS_ALL 4 63#define ENV_LAST 5 64 65const char *envdef[ENV_LAST] = { 66 "LD_TRACE_LOADED_OBJECTS", 67 "LD_TRACE_LOADED_OBJECTS_FMT1", 68 "LD_TRACE_LOADED_OBJECTS_FMT2", 69 "LD_TRACE_LOADED_OBJECTS_PROGNAME", 70 "LD_TRACE_LOADED_OBJECTS_ALL", 71}; 72 73int 74main(int argc, char *argv[]) 75{ 76 char *fmt1, *fmt2; 77 int rval, c, aflag, vflag; 78 79 aflag = vflag = 0; 80 fmt1 = fmt2 = NULL; 81 82 while ((c = getopt(argc, argv, "af:v")) != -1) { 83 switch (c) { 84 case 'a': 85 aflag++; 86 break; 87 case 'f': 88 if (fmt1 != NULL) { 89 if (fmt2 != NULL) 90 errx(1, "too many formats"); 91 fmt2 = optarg; 92 } else 93 fmt1 = optarg; 94 break; 95 case 'v': 96 vflag++; 97 break; 98 default: 99 usage(); 100 /* NOTREACHED */ 101 } 102 } 103 argc -= optind; 104 argv += optind; 105 106 if (vflag && fmt1 != NULL) 107 errx(1, "-v may not be used with -f"); 108 109 if (argc <= 0) { 110 usage(); 111 /* NOTREACHED */ 112 } 113 114#ifdef __i386__ 115 if (vflag) { 116 for (c = 0; c < argc; c++) 117 dump_file(argv[c]); 118 exit(error_count == 0 ? EXIT_SUCCESS : EXIT_FAILURE); 119 } 120#endif 121 122 rval = 0; 123 for (; argc > 0; argc--, argv++) { 124 int fd, status, is_shlib, rv, type; 125 const char **env; 126 127 env = envdef; /* Temporary placeholder */ 128 129 if ((fd = open(*argv, O_RDONLY, 0)) < 0) { 130 warn("%s", *argv); 131 rval |= 1; 132 continue; 133 } 134 rv = is_executable(*argv, fd, &is_shlib, &type); 135 close(fd); 136 if (rv == 0) { 137 rval |= 1; 138 continue; 139 } 140 141 /* ld.so magic */ 142 setenv(env[ENV_OBJECTS], "yes", 1); 143 if (fmt1 != NULL) 144 setenv(env[ENV_OBJECTS_FMT1], fmt1, 1); 145 if (fmt2 != NULL) 146 setenv(env[ENV_OBJECTS_FMT2], fmt2, 1); 147 148 setenv(env[ENV_OBJECTS_PROGNAME], *argv, 1); 149 if (aflag) 150 setenv(env[ENV_OBJECTS_ALL], "1", 1); 151 else if (fmt1 == NULL && fmt2 == NULL) 152 /* Default formats */ 153 printf("%s:\n", *argv); 154 fflush(stdout); 155 156 switch (fork()) { 157 case -1: 158 err(1, "fork"); 159 break; 160 default: 161 if (wait(&status) <= 0) { 162 warn("wait"); 163 rval |= 1; 164 } else if (WIFSIGNALED(status)) { 165 fprintf(stderr, "%s: signal %d\n", *argv, 166 WTERMSIG(status)); 167 rval |= 1; 168 } else if (WIFEXITED(status) && WEXITSTATUS(status)) { 169 fprintf(stderr, "%s: exit status %d\n", *argv, 170 WEXITSTATUS(status)); 171 rval |= 1; 172 } 173 break; 174 case 0: 175 if (is_shlib == 0) { 176 execl(*argv, *argv, (char *)NULL); 177 warn("%s", *argv); 178 } else { 179 dlopen(*argv, RTLD_TRACE); 180 warnx("%s: %s", *argv, dlerror()); 181 } 182 _exit(1); 183 } 184 } 185 186 return rval; 187} 188 189static void 190usage(void) 191{ 192 193 fprintf(stderr, "usage: ldd [-a] [-v] [-f format] program ...\n"); 194 exit(1); 195} 196 197static int 198is_executable(const char *fname, int fd, int *is_shlib, int *type) 199{ 200 union { 201 struct exec aout; 202 Elf_Ehdr elf; 203 } hdr; 204 int n; 205 206 *is_shlib = 0; 207 *type = TYPE_UNKNOWN; 208 209 if ((n = read(fd, &hdr, sizeof(hdr))) == -1) { 210 warn("%s: can't read program header", fname); 211 return (0); 212 } 213 214 if ((size_t)n >= sizeof(hdr.aout) && !N_BADMAG(hdr.aout)) { 215 /* a.out file */ 216 if ((N_GETFLAG(hdr.aout) & EX_DPMASK) != EX_DYNAMIC 217#if 1 /* Compatibility */ 218 || hdr.aout.a_entry < __LDPGSZ 219#endif 220 ) { 221 warnx("%s: not a dynamic executable", fname); 222 return (0); 223 } 224 *type = TYPE_AOUT; 225 return (1); 226 } 227 228 if ((size_t)n >= sizeof(hdr.elf) && IS_ELF(hdr.elf) && 229 hdr.elf.e_ident[EI_CLASS] == ELF_TARG_CLASS) { 230 /* Handle default ELF objects on this architecture */ 231 Elf_Phdr phdr; 232 int dynamic, i; 233 234 dynamic = 0; 235 *type = TYPE_ELF; 236 237 if (lseek(fd, hdr.elf.e_phoff, SEEK_SET) == -1) { 238 warnx("%s: header too short", fname); 239 return (0); 240 } 241 for (i = 0; i < hdr.elf.e_phnum; i++) { 242 if (read(fd, &phdr, hdr.elf.e_phentsize) 243 != sizeof(phdr)) { 244 warnx("%s: can't read program header", fname); 245 return (0); 246 } 247 if (phdr.p_type == PT_DYNAMIC) { 248 dynamic = 1; 249 break; 250 } 251 } 252 253 if (!dynamic) { 254 warnx("%s: not a dynamic ELF executable", fname); 255 return (0); 256 } 257 if (hdr.elf.e_type == ET_DYN) { 258 if (hdr.elf.e_ident[EI_OSABI] & ELFOSABI_FREEBSD) { 259 *is_shlib = 1; 260 return (1); 261 } 262 warnx("%s: not a FreeBSD ELF shared object", fname); 263 return (0); 264 } 265 266 return (1); 267 } 268 269 warnx("%s: not a dynamic executable", fname); 270 return (0); 271} 272