ldd.c revision 180877
1696Spaul/* 2696Spaul * Copyright (c) 1993 Paul Kranenburg 3696Spaul * All rights reserved. 4696Spaul * 5696Spaul * Redistribution and use in source and binary forms, with or without 6696Spaul * modification, are permitted provided that the following conditions 7696Spaul * are met: 8696Spaul * 1. Redistributions of source code must retain the above copyright 9696Spaul * notice, this list of conditions and the following disclaimer. 10696Spaul * 2. Redistributions in binary form must reproduce the above copyright 11696Spaul * notice, this list of conditions and the following disclaimer in the 12696Spaul * documentation and/or other materials provided with the distribution. 13696Spaul * 3. All advertising materials mentioning features or use of this software 14696Spaul * must display the following acknowledgement: 15696Spaul * This product includes software developed by Paul Kranenburg. 16696Spaul * 4. The name of the author may not be used to endorse or promote products 171153Sjkh * derived from this software without specific prior written permission 18696Spaul * 19696Spaul * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20696Spaul * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21696Spaul * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22696Spaul * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23696Spaul * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24696Spaul * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25696Spaul * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26696Spaul * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27696Spaul * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28696Spaul * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29696Spaul */ 30696Spaul 3195648Smarkm#include <sys/cdefs.h> 3295648Smarkm__FBSDID("$FreeBSD: head/usr.bin/ldd/ldd.c 180877 2008-07-28 12:49:16Z edwin $"); 3369827Scharnier 34696Spaul#include <sys/wait.h> 3595648Smarkm 3676224Sobrien#include <machine/elf.h> 3795648Smarkm 3895153Smike#include <arpa/inet.h> 3995648Smarkm 40696Spaul#include <a.out.h> 4190172Ssobomax#include <dlfcn.h> 421741Srich#include <err.h> 43180236Sedwin#include <errno.h> 441741Srich#include <fcntl.h> 451741Srich#include <stdio.h> 461741Srich#include <stdlib.h> 471741Srich#include <unistd.h> 48696Spaul 4995648Smarkm#include "extern.h" 5018600Speter 51180646Sedwin/* 52180877Sedwin * 32-bit ELF data structures can only be used if the system header[s] declare 53180877Sedwin * them. There is no official macro for determining whether they are declared, 54180877Sedwin * so check for the existence of one of the 32-macros defined in elf(5). 55180646Sedwin */ 56180877Sedwin#ifdef ELF32_R_TYPE 57180877Sedwin#define ELF32_SUPPORTED 58180646Sedwin#endif 59180646Sedwin 60180235Sedwinstatic int is_executable(const char *fname, int fd, int *is_shlib, 61180235Sedwin int *type); 62180235Sedwinstatic void usage(void); 63180234Sedwin 64180235Sedwin#define TYPE_UNKNOWN 0 65180235Sedwin#define TYPE_AOUT 1 66180235Sedwin#define TYPE_ELF 2 /* Architecture default */ 67180646Sedwin#if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED) 68180236Sedwin#define TYPE_ELF32 3 /* Explicit 32 bits on architectures >32 bits */ 69180236Sedwin#endif 70696Spaul 71180235Sedwin#define ENV_OBJECTS 0 72180235Sedwin#define ENV_OBJECTS_FMT1 1 73180235Sedwin#define ENV_OBJECTS_FMT2 2 74180235Sedwin#define ENV_OBJECTS_PROGNAME 3 75180235Sedwin#define ENV_OBJECTS_ALL 4 76180235Sedwin#define ENV_LAST 5 77180235Sedwin 78180235Sedwinconst char *envdef[ENV_LAST] = { 79180235Sedwin "LD_TRACE_LOADED_OBJECTS", 80180235Sedwin "LD_TRACE_LOADED_OBJECTS_FMT1", 81180235Sedwin "LD_TRACE_LOADED_OBJECTS_FMT2", 82180235Sedwin "LD_TRACE_LOADED_OBJECTS_PROGNAME", 83180235Sedwin "LD_TRACE_LOADED_OBJECTS_ALL", 84180235Sedwin}; 85180646Sedwin#if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED) 86180236Sedwinconst char *env32[ENV_LAST] = { 87180236Sedwin "LD_32_TRACE_LOADED_OBJECTS", 88180236Sedwin "LD_32_TRACE_LOADED_OBJECTS_FMT1", 89180236Sedwin "LD_32_TRACE_LOADED_OBJECTS_FMT2", 90180236Sedwin "LD_32_TRACE_LOADED_OBJECTS_PROGNAME", 91180236Sedwin "LD_32_TRACE_LOADED_OBJECTS_ALL", 92180236Sedwin}; 93180236Sedwin#endif 94180235Sedwin 95696Spaulint 9695648Smarkmmain(int argc, char *argv[]) 97696Spaul{ 98180234Sedwin char *fmt1, *fmt2; 99180234Sedwin int rval, c, aflag, vflag; 100696Spaul 10190755Sobrien aflag = vflag = 0; 102180234Sedwin fmt1 = fmt2 = NULL; 10390755Sobrien 104180234Sedwin while ((c = getopt(argc, argv, "af:v")) != -1) { 105696Spaul switch (c) { 10690755Sobrien case 'a': 10790755Sobrien aflag++; 10890755Sobrien break; 10918598Speter case 'f': 110180234Sedwin if (fmt1 != NULL) { 111180234Sedwin if (fmt2 != NULL) 11269827Scharnier errx(1, "too many formats"); 11318598Speter fmt2 = optarg; 11418598Speter } else 11518598Speter fmt1 = optarg; 11618598Speter break; 117180234Sedwin case 'v': 118180234Sedwin vflag++; 119180234Sedwin break; 120696Spaul default: 121696Spaul usage(); 122180234Sedwin /* NOTREACHED */ 123696Spaul } 124696Spaul } 125696Spaul argc -= optind; 126696Spaul argv += optind; 127696Spaul 128180234Sedwin if (vflag && fmt1 != NULL) 12918600Speter errx(1, "-v may not be used with -f"); 13018600Speter 131696Spaul if (argc <= 0) { 132696Spaul usage(); 133180234Sedwin /* NOTREACHED */ 134696Spaul } 135696Spaul 13639354Sdfr#ifdef __i386__ 13718600Speter if (vflag) { 13818600Speter for (c = 0; c < argc; c++) 13918600Speter dump_file(argv[c]); 14018600Speter exit(error_count == 0 ? EXIT_SUCCESS : EXIT_FAILURE); 14118600Speter } 14239354Sdfr#endif 14318600Speter 1441741Srich rval = 0; 145180234Sedwin for (; argc > 0; argc--, argv++) { 146180235Sedwin int fd, status, is_shlib, rv, type; 147180235Sedwin const char **env; 148696Spaul 149696Spaul if ((fd = open(*argv, O_RDONLY, 0)) < 0) { 1501741Srich warn("%s", *argv); 151696Spaul rval |= 1; 152696Spaul continue; 153696Spaul } 154180235Sedwin rv = is_executable(*argv, fd, &is_shlib, &type); 155180235Sedwin close(fd); 156180235Sedwin if (rv == 0) { 157696Spaul rval |= 1; 158696Spaul continue; 159696Spaul } 16035575Sdfr 161180236Sedwin switch (type) { 162180236Sedwin case TYPE_ELF: 163180236Sedwin case TYPE_AOUT: 164180236Sedwin env = envdef; 165180236Sedwin break; 166180646Sedwin#if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED) 167180236Sedwin case TYPE_ELF32: 168180236Sedwin env = env32; 169180236Sedwin break; 170180236Sedwin#endif 171180236Sedwin case TYPE_UNKNOWN: 172180236Sedwin default: 173180236Sedwin /* 174180236Sedwin * This shouldn't happen unless is_executable() 175180236Sedwin * is broken. 176180236Sedwin */ 177180236Sedwin errx(EDOOFUS, "unknown executable type"); 178180236Sedwin } 179180236Sedwin 180180235Sedwin /* ld.so magic */ 181180235Sedwin setenv(env[ENV_OBJECTS], "yes", 1); 182180235Sedwin if (fmt1 != NULL) 183180235Sedwin setenv(env[ENV_OBJECTS_FMT1], fmt1, 1); 184180235Sedwin if (fmt2 != NULL) 185180235Sedwin setenv(env[ENV_OBJECTS_FMT2], fmt2, 1); 18635575Sdfr 187180235Sedwin setenv(env[ENV_OBJECTS_PROGNAME], *argv, 1); 188180234Sedwin if (aflag) 189180235Sedwin setenv(env[ENV_OBJECTS_ALL], "1", 1); 19090755Sobrien else if (fmt1 == NULL && fmt2 == NULL) 19118598Speter /* Default formats */ 19218598Speter printf("%s:\n", *argv); 1931153Sjkh fflush(stdout); 194696Spaul 195696Spaul switch (fork()) { 196696Spaul case -1: 1971741Srich err(1, "fork"); 198696Spaul break; 199696Spaul default: 2001741Srich if (wait(&status) <= 0) { 2011741Srich warn("wait"); 2021741Srich rval |= 1; 2031741Srich } else if (WIFSIGNALED(status)) { 204180234Sedwin fprintf(stderr, "%s: signal %d\n", *argv, 205180234Sedwin WTERMSIG(status)); 206696Spaul rval |= 1; 207696Spaul } else if (WIFEXITED(status) && WEXITSTATUS(status)) { 208180234Sedwin fprintf(stderr, "%s: exit status %d\n", *argv, 209180234Sedwin WEXITSTATUS(status)); 210696Spaul rval |= 1; 211696Spaul } 212696Spaul break; 213696Spaul case 0: 214105439Ssobomax if (is_shlib == 0) { 21590172Ssobomax execl(*argv, *argv, (char *)NULL); 21690172Ssobomax warn("%s", *argv); 217105439Ssobomax } else { 218105439Ssobomax dlopen(*argv, RTLD_TRACE); 219105439Ssobomax warnx("%s: %s", *argv, dlerror()); 22090172Ssobomax } 221696Spaul _exit(1); 222696Spaul } 223696Spaul } 224696Spaul 225696Spaul return rval; 226696Spaul} 227180235Sedwin 228180235Sedwinstatic void 229180235Sedwinusage(void) 230180235Sedwin{ 231180235Sedwin 232180235Sedwin fprintf(stderr, "usage: ldd [-a] [-v] [-f format] program ...\n"); 233180235Sedwin exit(1); 234180235Sedwin} 235180235Sedwin 236180235Sedwinstatic int 237180235Sedwinis_executable(const char *fname, int fd, int *is_shlib, int *type) 238180235Sedwin{ 239180235Sedwin union { 240180235Sedwin struct exec aout; 241180646Sedwin#if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED) 242180236Sedwin Elf32_Ehdr elf32; 243180646Sedwin#endif 244180235Sedwin Elf_Ehdr elf; 245180235Sedwin } hdr; 246180235Sedwin int n; 247180235Sedwin 248180235Sedwin *is_shlib = 0; 249180235Sedwin *type = TYPE_UNKNOWN; 250180235Sedwin 251180235Sedwin if ((n = read(fd, &hdr, sizeof(hdr))) == -1) { 252180235Sedwin warn("%s: can't read program header", fname); 253180235Sedwin return (0); 254180235Sedwin } 255180235Sedwin 256180235Sedwin if ((size_t)n >= sizeof(hdr.aout) && !N_BADMAG(hdr.aout)) { 257180235Sedwin /* a.out file */ 258180235Sedwin if ((N_GETFLAG(hdr.aout) & EX_DPMASK) != EX_DYNAMIC 259180235Sedwin#if 1 /* Compatibility */ 260180235Sedwin || hdr.aout.a_entry < __LDPGSZ 261180235Sedwin#endif 262180235Sedwin ) { 263180235Sedwin warnx("%s: not a dynamic executable", fname); 264180235Sedwin return (0); 265180235Sedwin } 266180235Sedwin *type = TYPE_AOUT; 267180235Sedwin return (1); 268180235Sedwin } 269180235Sedwin 270180646Sedwin#if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED) 271180236Sedwin if ((size_t)n >= sizeof(hdr.elf32) && IS_ELF(hdr.elf32) && 272180236Sedwin hdr.elf32.e_ident[EI_CLASS] == ELFCLASS32) { 273180236Sedwin /* Handle 32 bit ELF objects */ 274180236Sedwin Elf32_Phdr phdr; 275180236Sedwin int dynamic, i; 276180236Sedwin 277180236Sedwin dynamic = 0; 278180236Sedwin *type = TYPE_ELF32; 279180236Sedwin 280180236Sedwin if (lseek(fd, hdr.elf32.e_phoff, SEEK_SET) == -1) { 281180236Sedwin warnx("%s: header too short", fname); 282180236Sedwin return (0); 283180236Sedwin } 284180236Sedwin for (i = 0; i < hdr.elf32.e_phnum; i++) { 285180236Sedwin if (read(fd, &phdr, hdr.elf32.e_phentsize) != 286180236Sedwin sizeof(phdr)) { 287180236Sedwin warnx("%s: can't read program header", fname); 288180236Sedwin return (0); 289180236Sedwin } 290180236Sedwin if (phdr.p_type == PT_DYNAMIC) { 291180236Sedwin dynamic = 1; 292180236Sedwin break; 293180236Sedwin } 294180236Sedwin } 295180236Sedwin 296180236Sedwin if (!dynamic) { 297180236Sedwin warnx("%s: not a dynamic ELF executable", fname); 298180236Sedwin return (0); 299180236Sedwin } 300180236Sedwin if (hdr.elf32.e_type == ET_DYN) { 301180236Sedwin if (hdr.elf32.e_ident[EI_OSABI] & ELFOSABI_FREEBSD) { 302180236Sedwin *is_shlib = 1; 303180236Sedwin return (1); 304180236Sedwin } 305180236Sedwin warnx("%s: not a FreeBSD ELF shared object", fname); 306180236Sedwin return (0); 307180236Sedwin } 308180236Sedwin 309180236Sedwin return (1); 310180236Sedwin } 311180236Sedwin#endif 312180236Sedwin 313180235Sedwin if ((size_t)n >= sizeof(hdr.elf) && IS_ELF(hdr.elf) && 314180235Sedwin hdr.elf.e_ident[EI_CLASS] == ELF_TARG_CLASS) { 315180235Sedwin /* Handle default ELF objects on this architecture */ 316180235Sedwin Elf_Phdr phdr; 317180235Sedwin int dynamic, i; 318180235Sedwin 319180235Sedwin dynamic = 0; 320180235Sedwin *type = TYPE_ELF; 321180235Sedwin 322180235Sedwin if (lseek(fd, hdr.elf.e_phoff, SEEK_SET) == -1) { 323180235Sedwin warnx("%s: header too short", fname); 324180235Sedwin return (0); 325180235Sedwin } 326180235Sedwin for (i = 0; i < hdr.elf.e_phnum; i++) { 327180235Sedwin if (read(fd, &phdr, hdr.elf.e_phentsize) 328180235Sedwin != sizeof(phdr)) { 329180235Sedwin warnx("%s: can't read program header", fname); 330180235Sedwin return (0); 331180235Sedwin } 332180235Sedwin if (phdr.p_type == PT_DYNAMIC) { 333180235Sedwin dynamic = 1; 334180235Sedwin break; 335180235Sedwin } 336180235Sedwin } 337180235Sedwin 338180235Sedwin if (!dynamic) { 339180235Sedwin warnx("%s: not a dynamic ELF executable", fname); 340180235Sedwin return (0); 341180235Sedwin } 342180235Sedwin if (hdr.elf.e_type == ET_DYN) { 343180235Sedwin if (hdr.elf.e_ident[EI_OSABI] & ELFOSABI_FREEBSD) { 344180235Sedwin *is_shlib = 1; 345180235Sedwin return (1); 346180235Sedwin } 347180235Sedwin warnx("%s: not a FreeBSD ELF shared object", fname); 348180235Sedwin return (0); 349180235Sedwin } 350180235Sedwin 351180235Sedwin return (1); 352180235Sedwin } 353180235Sedwin 354180235Sedwin warnx("%s: not a dynamic executable", fname); 355180235Sedwin return (0); 356180235Sedwin} 357