ldd.c revision 105439
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 105439 2002-10-19 10:18:29Z sobomax $"); 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> 431741Srich#include <fcntl.h> 441741Srich#include <stdio.h> 451741Srich#include <stdlib.h> 461741Srich#include <unistd.h> 47696Spaul 4895648Smarkm#include "extern.h" 4918600Speter 5095648Smarkmstatic void 5195648Smarkmusage(void) 52696Spaul{ 5390755Sobrien fprintf(stderr, "usage: ldd [-a] [-v] [-f format] program ...\n"); 541741Srich exit(1); 55696Spaul} 56696Spaul 57696Spaulint 5895648Smarkmmain(int argc, char *argv[]) 59696Spaul{ 6018598Speter char *fmt1 = NULL, *fmt2 = NULL; 611741Srich int rval; 62696Spaul int c; 6390755Sobrien int aflag, vflag; 64696Spaul 6590755Sobrien aflag = vflag = 0; 6690755Sobrien 6790755Sobrien while ((c = getopt(argc, argv, "avf:")) != -1) { 68696Spaul switch (c) { 6990755Sobrien case 'a': 7090755Sobrien aflag++; 7190755Sobrien break; 7218600Speter case 'v': 7318600Speter vflag++; 7418600Speter break; 7518598Speter case 'f': 7618598Speter if (fmt1) { 7718598Speter if (fmt2) 7869827Scharnier errx(1, "too many formats"); 7918598Speter fmt2 = optarg; 8018598Speter } else 8118598Speter fmt1 = optarg; 8218598Speter break; 83696Spaul default: 84696Spaul usage(); 851741Srich /*NOTREACHED*/ 86696Spaul } 87696Spaul } 88696Spaul argc -= optind; 89696Spaul argv += optind; 90696Spaul 9118600Speter if (vflag && fmt1) 9218600Speter errx(1, "-v may not be used with -f"); 9318600Speter 94696Spaul if (argc <= 0) { 95696Spaul usage(); 961741Srich /*NOTREACHED*/ 97696Spaul } 98696Spaul 9939354Sdfr#ifdef __i386__ 10018600Speter if (vflag) { 10118600Speter for (c = 0; c < argc; c++) 10218600Speter dump_file(argv[c]); 10318600Speter exit(error_count == 0 ? EXIT_SUCCESS : EXIT_FAILURE); 10418600Speter } 10539354Sdfr#endif 10618600Speter 107696Spaul /* ld.so magic */ 10890755Sobrien setenv("LD_TRACE_LOADED_OBJECTS", "yes", 1); 10918598Speter if (fmt1) 11018598Speter setenv("LD_TRACE_LOADED_OBJECTS_FMT1", fmt1, 1); 11118598Speter if (fmt2) 11218598Speter setenv("LD_TRACE_LOADED_OBJECTS_FMT2", fmt2, 1); 113696Spaul 1141741Srich rval = 0; 11538648Sjdp for ( ; argc > 0; argc--, argv++) { 116696Spaul int fd; 11738648Sjdp union { 11838648Sjdp struct exec aout; 11939354Sdfr Elf_Ehdr elf; 12038648Sjdp } hdr; 12138648Sjdp int n; 122696Spaul int status; 12338648Sjdp int file_ok; 12490172Ssobomax int is_shlib; 125696Spaul 126696Spaul if ((fd = open(*argv, O_RDONLY, 0)) < 0) { 1271741Srich warn("%s", *argv); 128696Spaul rval |= 1; 129696Spaul continue; 130696Spaul } 13138648Sjdp if ((n = read(fd, &hdr, sizeof hdr)) == -1) { 13238648Sjdp warn("%s: can't read program header", *argv); 133696Spaul (void)close(fd); 134696Spaul rval |= 1; 135696Spaul continue; 136696Spaul } 13735575Sdfr 13838648Sjdp file_ok = 1; 13990172Ssobomax is_shlib = 0; 14095648Smarkm if ((size_t)n >= sizeof hdr.aout && !N_BADMAG(hdr.aout)) { 14135575Sdfr /* a.out file */ 14238648Sjdp if ((N_GETFLAG(hdr.aout) & EX_DPMASK) != EX_DYNAMIC 14335575Sdfr#if 1 /* Compatibility */ 14438648Sjdp || hdr.aout.a_entry < __LDPGSZ 14535575Sdfr#endif 14635575Sdfr ) { 14735575Sdfr warnx("%s: not a dynamic executable", *argv); 14838648Sjdp file_ok = 0; 14935575Sdfr } 15095648Smarkm } else if ((size_t)n >= sizeof hdr.elf && IS_ELF(hdr.elf)) { 15139354Sdfr Elf_Ehdr ehdr; 15239354Sdfr Elf_Phdr phdr; 15335575Sdfr int dynamic = 0, i; 15435575Sdfr 15570049Sache if (lseek(fd, 0, SEEK_SET) == -1 || 15670049Sache read(fd, &ehdr, sizeof ehdr) != sizeof ehdr || 15770049Sache lseek(fd, ehdr.e_phoff, SEEK_SET) == -1 15870049Sache ) { 15935575Sdfr warnx("%s: can't read program header", *argv); 16038648Sjdp file_ok = 0; 16170049Sache } else { 16270049Sache for (i = 0; i < ehdr.e_phnum; i++) { 16370049Sache if (read(fd, &phdr, ehdr.e_phentsize) 16470049Sache != sizeof phdr) { 16570049Sache warnx("%s: can't read program header", 16670049Sache *argv); 16770049Sache file_ok = 0; 16870049Sache break; 16970049Sache } 17070049Sache if (phdr.p_type == PT_DYNAMIC) 17170049Sache dynamic = 1; 17235575Sdfr } 17335575Sdfr } 17435575Sdfr if (!dynamic) { 17535575Sdfr warnx("%s: not a dynamic executable", *argv); 17638648Sjdp file_ok = 0; 17790172Ssobomax } else if (hdr.elf.e_type == ET_DYN) { 17890385Ssobomax if (hdr.elf.e_ident[EI_OSABI] & ELFOSABI_FREEBSD) { 17990385Ssobomax is_shlib = 1; 18090385Ssobomax } else { 18190385Ssobomax warnx("%s: not a FreeBSD ELF shared " 18290385Ssobomax "object", *argv); 18390385Ssobomax file_ok = 0; 18490385Ssobomax } 18535575Sdfr } 18638648Sjdp } else { 18738648Sjdp warnx("%s: not a dynamic executable", *argv); 18838648Sjdp file_ok = 0; 18935575Sdfr } 190696Spaul (void)close(fd); 19138648Sjdp if (!file_ok) { 19238648Sjdp rval |= 1; 19338648Sjdp continue; 19438648Sjdp } 195696Spaul 19618598Speter setenv("LD_TRACE_LOADED_OBJECTS_PROGNAME", *argv, 1); 19790755Sobrien if (aflag) setenv("LD_TRACE_LOADED_OBJECTS_ALL", "1", 1); 19890755Sobrien else if (fmt1 == NULL && fmt2 == NULL) 19918598Speter /* Default formats */ 20018598Speter printf("%s:\n", *argv); 20118598Speter 2021153Sjkh fflush(stdout); 203696Spaul 204696Spaul switch (fork()) { 205696Spaul case -1: 2061741Srich err(1, "fork"); 207696Spaul break; 208696Spaul default: 2091741Srich if (wait(&status) <= 0) { 2101741Srich warn("wait"); 2111741Srich rval |= 1; 2121741Srich } else if (WIFSIGNALED(status)) { 213696Spaul fprintf(stderr, "%s: signal %d\n", 214696Spaul *argv, WTERMSIG(status)); 215696Spaul rval |= 1; 216696Spaul } else if (WIFEXITED(status) && WEXITSTATUS(status)) { 217696Spaul fprintf(stderr, "%s: exit status %d\n", 218696Spaul *argv, WEXITSTATUS(status)); 219696Spaul rval |= 1; 220696Spaul } 221696Spaul break; 222696Spaul case 0: 223105439Ssobomax if (is_shlib == 0) { 22490172Ssobomax execl(*argv, *argv, (char *)NULL); 22590172Ssobomax warn("%s", *argv); 226105439Ssobomax } else { 227105439Ssobomax dlopen(*argv, RTLD_TRACE); 228105439Ssobomax warnx("%s: %s", *argv, dlerror()); 22990172Ssobomax } 230696Spaul _exit(1); 231696Spaul } 232696Spaul } 233696Spaul 234696Spaul return rval; 235696Spaul} 236