ldd.c revision 180234
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 180234 2008-07-03 22:26:43Z 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 void 51usage(void) 52{ 53 54 fprintf(stderr, "usage: ldd [-a] [-v] [-f format] program ...\n"); 55 exit(1); 56} 57 58int 59main(int argc, char *argv[]) 60{ 61 char *fmt1, *fmt2; 62 int rval, c, aflag, vflag; 63 64 aflag = vflag = 0; 65 fmt1 = fmt2 = NULL; 66 67 while ((c = getopt(argc, argv, "af:v")) != -1) { 68 switch (c) { 69 case 'a': 70 aflag++; 71 break; 72 case 'f': 73 if (fmt1 != NULL) { 74 if (fmt2 != NULL) 75 errx(1, "too many formats"); 76 fmt2 = optarg; 77 } else 78 fmt1 = optarg; 79 break; 80 case 'v': 81 vflag++; 82 break; 83 default: 84 usage(); 85 /* NOTREACHED */ 86 } 87 } 88 argc -= optind; 89 argv += optind; 90 91 if (vflag && fmt1 != NULL) 92 errx(1, "-v may not be used with -f"); 93 94 if (argc <= 0) { 95 usage(); 96 /* NOTREACHED */ 97 } 98 99#ifdef __i386__ 100 if (vflag) { 101 for (c = 0; c < argc; c++) 102 dump_file(argv[c]); 103 exit(error_count == 0 ? EXIT_SUCCESS : EXIT_FAILURE); 104 } 105#endif 106 107 /* ld.so magic */ 108 setenv("LD_TRACE_LOADED_OBJECTS", "yes", 1); 109 if (fmt1 != NULL) 110 setenv("LD_TRACE_LOADED_OBJECTS_FMT1", fmt1, 1); 111 if (fmt2 != NULL) 112 setenv("LD_TRACE_LOADED_OBJECTS_FMT2", fmt2, 1); 113 114 rval = 0; 115 for (; argc > 0; argc--, argv++) { 116 int fd, n, status, file_ok, is_shlib; 117 union { 118 struct exec aout; 119 Elf_Ehdr elf; 120 } hdr; 121 122 if ((fd = open(*argv, O_RDONLY, 0)) < 0) { 123 warn("%s", *argv); 124 rval |= 1; 125 continue; 126 } 127 if ((n = read(fd, &hdr, sizeof(hdr))) == -1) { 128 warn("%s: can't read program header", *argv); 129 close(fd); 130 rval |= 1; 131 continue; 132 } 133 134 file_ok = 1; 135 is_shlib = 0; 136 if ((size_t)n >= sizeof(hdr.aout) && !N_BADMAG(hdr.aout)) { 137 /* a.out file */ 138 if ((N_GETFLAG(hdr.aout) & EX_DPMASK) != EX_DYNAMIC 139#if 1 /* Compatibility */ 140 || hdr.aout.a_entry < __LDPGSZ 141#endif 142 ) { 143 warnx("%s: not a dynamic executable", *argv); 144 file_ok = 0; 145 } 146 } else if ((size_t)n >= sizeof(hdr.elf) && IS_ELF(hdr.elf)) { 147 Elf_Ehdr ehdr; 148 Elf_Phdr phdr; 149 int dynamic, i; 150 151 dynamic = 0; 152 153 if (lseek(fd, 0, SEEK_SET) == -1 || 154 read(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr) || 155 lseek(fd, ehdr.e_phoff, SEEK_SET) == -1) { 156 warnx("%s: can't read program header", *argv); 157 file_ok = 0; 158 } else { 159 for (i = 0; i < ehdr.e_phnum; i++) { 160 if (read(fd, &phdr, ehdr.e_phentsize) 161 != sizeof(phdr)) { 162 warnx("%s: can't read program header", 163 *argv); 164 file_ok = 0; 165 break; 166 } 167 if (phdr.p_type == PT_DYNAMIC) 168 dynamic = 1; 169 } 170 } 171 if (!dynamic) { 172 warnx("%s: not a dynamic executable", *argv); 173 file_ok = 0; 174 } else if (hdr.elf.e_type == ET_DYN) { 175 if (hdr.elf.e_ident[EI_OSABI] & ELFOSABI_FREEBSD) { 176 is_shlib = 1; 177 } else { 178 warnx("%s: not a FreeBSD ELF shared " 179 "object", *argv); 180 file_ok = 0; 181 } 182 } 183 } else { 184 warnx("%s: not a dynamic executable", *argv); 185 file_ok = 0; 186 } 187 close(fd); 188 if (!file_ok) { 189 rval |= 1; 190 continue; 191 } 192 193 setenv("LD_TRACE_LOADED_OBJECTS_PROGNAME", *argv, 1); 194 if (aflag) 195 setenv("LD_TRACE_LOADED_OBJECTS_ALL", "1", 1); 196 else if (fmt1 == NULL && fmt2 == NULL) 197 /* Default formats */ 198 printf("%s:\n", *argv); 199 fflush(stdout); 200 201 switch (fork()) { 202 case -1: 203 err(1, "fork"); 204 break; 205 default: 206 if (wait(&status) <= 0) { 207 warn("wait"); 208 rval |= 1; 209 } else if (WIFSIGNALED(status)) { 210 fprintf(stderr, "%s: signal %d\n", *argv, 211 WTERMSIG(status)); 212 rval |= 1; 213 } else if (WIFEXITED(status) && WEXITSTATUS(status)) { 214 fprintf(stderr, "%s: exit status %d\n", *argv, 215 WEXITSTATUS(status)); 216 rval |= 1; 217 } 218 break; 219 case 0: 220 if (is_shlib == 0) { 221 execl(*argv, *argv, (char *)NULL); 222 warn("%s", *argv); 223 } else { 224 dlopen(*argv, RTLD_TRACE); 225 warnx("%s: %s", *argv, dlerror()); 226 } 227 _exit(1); 228 } 229 } 230 231 return rval; 232} 233