ldd.c revision 294665
190075Sobrien/* 290075Sobrien * Copyright (c) 1993 Paul Kranenburg 3110611Skan * All rights reserved. 490075Sobrien * 590075Sobrien * Redistribution and use in source and binary forms, with or without 690075Sobrien * modification, are permitted provided that the following conditions 790075Sobrien * are met: 890075Sobrien * 1. Redistributions of source code must retain the above copyright 990075Sobrien * notice, this list of conditions and the following disclaimer. 1090075Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1190075Sobrien * notice, this list of conditions and the following disclaimer in the 1290075Sobrien * documentation and/or other materials provided with the distribution. 1390075Sobrien * 3. All advertising materials mentioning features or use of this software 1490075Sobrien * must display the following acknowledgement: 1590075Sobrien * This product includes software developed by Paul Kranenburg. 1690075Sobrien * 4. The name of the author may not be used to endorse or promote products 1790075Sobrien * derived from this software without specific prior written permission 1890075Sobrien * 1990075Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 2090075Sobrien * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2190075Sobrien * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2290075Sobrien * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2390075Sobrien * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2490075Sobrien * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25132718Skan * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26132718Skan * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2790075Sobrien * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2890075Sobrien * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2990075Sobrien */ 3096263Sobrien 3196263Sobrien#include <sys/cdefs.h> 3290075Sobrien__FBSDID("$FreeBSD: head/usr.bin/ldd/ldd.c 294665 2016-01-24 15:15:57Z br $"); 3396263Sobrien 3490075Sobrien#include <sys/wait.h> 3590075Sobrien 3690075Sobrien#include <machine/elf.h> 3790075Sobrien 3890075Sobrien#include <arpa/inet.h> 3990075Sobrien 4090075Sobrien#include <dlfcn.h> 4190075Sobrien#include <err.h> 4290075Sobrien#include <errno.h> 4390075Sobrien#include <fcntl.h> 4490075Sobrien#include <stdio.h> 4590075Sobrien#include <stdlib.h> 4690075Sobrien#include <string.h> 4790075Sobrien#include <unistd.h> 4890075Sobrien 49132718Skan#include "extern.h" 50132718Skan 51132718Skan/* We don't support a.out executables on arm64 and riscv */ 52132718Skan#if !defined(__aarch64__) && !defined(__riscv__) 53132718Skan#include <a.out.h> 54132718Skan#define AOUT_SUPPORTED 55132718Skan#endif 56132718Skan 5790075Sobrien/* 58107590Sobrien * 32-bit ELF data structures can only be used if the system header[s] declare 59107590Sobrien * them. There is no official macro for determining whether they are declared, 60107590Sobrien * so check for the existence of one of the 32-macros defined in elf(5). 61107590Sobrien */ 62132718Skan#ifdef ELF32_R_TYPE 63107590Sobrien#define ELF32_SUPPORTED 64107590Sobrien#endif 65107590Sobrien 66107590Sobrien#define LDD_SETENV(name, value, overwrite) do { \ 67132718Skan setenv("LD_" name, value, overwrite); \ 68117395Skan setenv("LD_32_" name, value, overwrite); \ 69107590Sobrien} while (0) 70107590Sobrien 71107590Sobrien#define LDD_UNSETENV(name) do { \ 72107590Sobrien unsetenv("LD_" name); \ 73107590Sobrien unsetenv("LD_32_" name); \ 74107590Sobrien} while (0) 75107590Sobrien 76107590Sobrienstatic int is_executable(const char *fname, int fd, int *is_shlib, 77107590Sobrien int *type); 78107590Sobrienstatic void usage(void); 79107590Sobrien 8090075Sobrien#define TYPE_UNKNOWN 0 8190075Sobrien#define TYPE_AOUT 1 8290075Sobrien#define TYPE_ELF 2 /* Architecture default */ 8390075Sobrien#if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED) 84132718Skan#define TYPE_ELF32 3 /* Explicit 32 bits on architectures >32 bits */ 8590075Sobrien 8690075Sobrien#define _PATH_LDD32 "/usr/bin/ldd32" 8790075Sobrien 8890075Sobrienstatic int 8990075Sobrienexecldd32(char *file, char *fmt1, char *fmt2, int aflag, int vflag) 9090075Sobrien{ 9190075Sobrien char *argv[8]; 92132718Skan int i, rval, status; 93107590Sobrien 9490075Sobrien LDD_UNSETENV("TRACE_LOADED_OBJECTS"); 9590075Sobrien rval = 0; 9690075Sobrien i = 0; 9790075Sobrien argv[i++] = strdup(_PATH_LDD32); 98107590Sobrien if (aflag) 9990075Sobrien argv[i++] = strdup("-a"); 10090075Sobrien if (vflag) 10190075Sobrien argv[i++] = strdup("-v"); 10290075Sobrien if (fmt1 != NULL) { 10390075Sobrien argv[i++] = strdup("-f"); 104132718Skan argv[i++] = strdup(fmt1); 10590075Sobrien } 106132718Skan if (fmt2 != NULL) { 107132718Skan argv[i++] = strdup("-f"); 10890075Sobrien argv[i++] = strdup(fmt2); 109117395Skan } 110117395Skan argv[i++] = strdup(file); 111117395Skan argv[i++] = NULL; 112132718Skan 11390075Sobrien switch (fork()) { 11490075Sobrien case -1: 11590075Sobrien err(1, "fork"); 11690075Sobrien break; 11790075Sobrien case 0: 11890075Sobrien execv(_PATH_LDD32, argv); 11990075Sobrien warn("%s", _PATH_LDD32); 120117395Skan _exit(127); 12190075Sobrien break; 12290075Sobrien default: 12390075Sobrien if (wait(&status) < 0) 12490075Sobrien rval = 1; 12590075Sobrien else if (WIFSIGNALED(status)) 12690075Sobrien rval = 1; 12790075Sobrien else if (WIFEXITED(status) && WEXITSTATUS(status) != 0) 12890075Sobrien rval = 1; 12990075Sobrien break; 130132718Skan } 13190075Sobrien while (i--) 13290075Sobrien free(argv[i]); 13390075Sobrien LDD_SETENV("TRACE_LOADED_OBJECTS", "yes", 1); 13490075Sobrien return (rval); 13590075Sobrien} 13690075Sobrien#endif 13790075Sobrien 13890075Sobrienint 13990075Sobrienmain(int argc, char *argv[]) 14090075Sobrien{ 14190075Sobrien char *fmt1, *fmt2; 142132718Skan int rval, c, aflag, vflag; 143132718Skan 14490075Sobrien aflag = vflag = 0; 14590075Sobrien fmt1 = fmt2 = NULL; 146132718Skan 14790075Sobrien while ((c = getopt(argc, argv, "af:v")) != -1) { 14890075Sobrien switch (c) { 14990075Sobrien case 'a': 150117395Skan aflag++; 15190075Sobrien break; 15290075Sobrien case 'f': 15390075Sobrien if (fmt1 != NULL) { 15490075Sobrien if (fmt2 != NULL) 15590075Sobrien errx(1, "too many formats"); 15690075Sobrien fmt2 = optarg; 15790075Sobrien } else 15890075Sobrien fmt1 = optarg; 15990075Sobrien break; 16090075Sobrien case 'v': 16190075Sobrien vflag++; 16290075Sobrien break; 16390075Sobrien default: 16490075Sobrien usage(); 16590075Sobrien /* NOTREACHED */ 16690075Sobrien } 16790075Sobrien } 16890075Sobrien argc -= optind; 16990075Sobrien argv += optind; 17090075Sobrien 17190075Sobrien if (vflag && fmt1 != NULL) 17290075Sobrien errx(1, "-v may not be used with -f"); 17390075Sobrien 17490075Sobrien if (argc <= 0) { 17590075Sobrien usage(); 17690075Sobrien /* NOTREACHED */ 17790075Sobrien } 17890075Sobrien 17990075Sobrien#ifdef __i386__ 18090075Sobrien if (vflag) { 18190075Sobrien for (c = 0; c < argc; c++) 18290075Sobrien dump_file(argv[c]); 18390075Sobrien exit(error_count == 0 ? EXIT_SUCCESS : EXIT_FAILURE); 18490075Sobrien } 18590075Sobrien#endif 18690075Sobrien 18790075Sobrien rval = 0; 18890075Sobrien for (; argc > 0; argc--, argv++) { 18990075Sobrien int fd, status, is_shlib, rv, type; 19090075Sobrien 19190075Sobrien if ((fd = open(*argv, O_RDONLY, 0)) < 0) { 19290075Sobrien warn("%s", *argv); 19390075Sobrien rval |= 1; 19490075Sobrien continue; 19590075Sobrien } 19690075Sobrien rv = is_executable(*argv, fd, &is_shlib, &type); 19790075Sobrien close(fd); 19890075Sobrien if (rv == 0) { 19990075Sobrien rval |= 1; 20090075Sobrien continue; 20190075Sobrien } 20290075Sobrien 20390075Sobrien switch (type) { 20490075Sobrien case TYPE_ELF: 20590075Sobrien case TYPE_AOUT: 20690075Sobrien break; 20790075Sobrien#if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED) 20890075Sobrien case TYPE_ELF32: 20990075Sobrien rval |= execldd32(*argv, fmt1, fmt2, aflag, vflag); 21090075Sobrien continue; 211117395Skan#endif 212117395Skan case TYPE_UNKNOWN: 213117395Skan default: 214132718Skan /* 215117395Skan * This shouldn't happen unless is_executable() 216117395Skan * is broken. 217117395Skan */ 218117395Skan errx(EDOOFUS, "unknown executable type"); 219117395Skan } 220117395Skan 221117395Skan /* ld.so magic */ 222117395Skan LDD_SETENV("TRACE_LOADED_OBJECTS", "yes", 1); 223117395Skan if (fmt1 != NULL) 224117395Skan LDD_SETENV("TRACE_LOADED_OBJECTS_FMT1", fmt1, 1); 225117395Skan if (fmt2 != NULL) 226117395Skan LDD_SETENV("TRACE_LOADED_OBJECTS_FMT2", fmt2, 1); 227117395Skan 228117395Skan LDD_SETENV("TRACE_LOADED_OBJECTS_PROGNAME", *argv, 1); 229117395Skan if (aflag) 230117395Skan LDD_SETENV("TRACE_LOADED_OBJECTS_ALL", "1", 1); 231132718Skan else if (fmt1 == NULL && fmt2 == NULL) 232117395Skan /* Default formats */ 233117395Skan printf("%s:\n", *argv); 234117395Skan fflush(stdout); 235132718Skan 236117395Skan switch (fork()) { 237132718Skan case -1: 238117395Skan err(1, "fork"); 239132718Skan break; 240117395Skan default: 241117395Skan if (wait(&status) < 0) { 242117395Skan warn("wait"); 243117395Skan rval |= 1; 244117395Skan } else if (WIFSIGNALED(status)) { 24590075Sobrien fprintf(stderr, "%s: signal %d\n", *argv, 24690075Sobrien WTERMSIG(status)); 24790075Sobrien rval |= 1; 24890075Sobrien } else if (WIFEXITED(status) && 249132718Skan WEXITSTATUS(status) != 0) { 25090075Sobrien fprintf(stderr, "%s: exit status %d\n", *argv, 25190075Sobrien WEXITSTATUS(status)); 25290075Sobrien rval |= 1; 25390075Sobrien } 25490075Sobrien break; 25590075Sobrien case 0: 25690075Sobrien if (is_shlib == 0) { 25790075Sobrien execl(*argv, *argv, (char *)NULL); 25890075Sobrien warn("%s", *argv); 25990075Sobrien } else { 26090075Sobrien dlopen(*argv, RTLD_TRACE); 26190075Sobrien warnx("%s: %s", *argv, dlerror()); 26290075Sobrien } 26390075Sobrien _exit(1); 26490075Sobrien } 26590075Sobrien } 26690075Sobrien 26790075Sobrien return rval; 26890075Sobrien} 26990075Sobrien 27090075Sobrienstatic void 27190075Sobrienusage(void) 27290075Sobrien{ 27390075Sobrien 27490075Sobrien fprintf(stderr, "usage: ldd [-a] [-v] [-f format] program ...\n"); 27590075Sobrien exit(1); 27690075Sobrien} 27790075Sobrien 278132718Skanstatic int 27990075Sobrienis_executable(const char *fname, int fd, int *is_shlib, int *type) 28090075Sobrien{ 28190075Sobrien union { 282117395Skan#ifdef AOUT_SUPPORTED 28390075Sobrien struct exec aout; 28490075Sobrien#endif 285117395Skan#if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED) 286117395Skan Elf32_Ehdr elf32; 28790075Sobrien#endif 28890075Sobrien Elf_Ehdr elf; 289117395Skan } hdr; 29090075Sobrien int n; 291117395Skan 29290075Sobrien *is_shlib = 0; 29390075Sobrien *type = TYPE_UNKNOWN; 29490075Sobrien 29590075Sobrien if ((n = read(fd, &hdr, sizeof(hdr))) == -1) { 29690075Sobrien warn("%s: can't read program header", fname); 29790075Sobrien return (0); 29890075Sobrien } 29990075Sobrien 30090075Sobrien#ifdef AOUT_SUPPORTED 30190075Sobrien if ((size_t)n >= sizeof(hdr.aout) && !N_BADMAG(hdr.aout)) { 30290075Sobrien /* a.out file */ 30390075Sobrien if ((N_GETFLAG(hdr.aout) & EX_DPMASK) != EX_DYNAMIC 30490075Sobrien#if 1 /* Compatibility */ 30596263Sobrien || hdr.aout.a_entry < __LDPGSZ 30690075Sobrien#endif 307117395Skan ) { 308132718Skan warnx("%s: not a dynamic executable", fname); 30990075Sobrien return (0); 31096263Sobrien } 311132718Skan *type = TYPE_AOUT; 31296263Sobrien return (1); 31396263Sobrien } 31490075Sobrien#endif 31596263Sobrien 31696263Sobrien#if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED) 31796263Sobrien if ((size_t)n >= sizeof(hdr.elf32) && IS_ELF(hdr.elf32) && 31896263Sobrien hdr.elf32.e_ident[EI_CLASS] == ELFCLASS32) { 31996263Sobrien /* Handle 32 bit ELF objects */ 32096263Sobrien Elf32_Phdr phdr; 321110611Skan int dynamic, i; 322110611Skan 323110611Skan dynamic = 0; 324110611Skan *type = TYPE_ELF32; 325110611Skan 32696263Sobrien if (lseek(fd, hdr.elf32.e_phoff, SEEK_SET) == -1) { 32790075Sobrien warnx("%s: header too short", fname); 32890075Sobrien return (0); 32990075Sobrien } 33090075Sobrien for (i = 0; i < hdr.elf32.e_phnum; i++) { 33190075Sobrien if (read(fd, &phdr, hdr.elf32.e_phentsize) != 33290075Sobrien sizeof(phdr)) { 333117395Skan warnx("%s: can't read program header", fname); 33490075Sobrien return (0); 335117395Skan } 336132718Skan if (phdr.p_type == PT_DYNAMIC) { 33790075Sobrien dynamic = 1; 33890075Sobrien break; 33990075Sobrien } 340117395Skan } 341117395Skan 342117395Skan if (!dynamic) { 343117395Skan warnx("%s: not a dynamic ELF executable", fname); 344117395Skan return (0); 345117395Skan } 346132718Skan if (hdr.elf32.e_type == ET_DYN) { 34790075Sobrien if (hdr.elf32.e_ident[EI_OSABI] == ELFOSABI_FREEBSD) { 34890075Sobrien *is_shlib = 1; 34990075Sobrien return (1); 35090075Sobrien } 35190075Sobrien warnx("%s: not a FreeBSD ELF shared object", fname); 35296263Sobrien return (0); 35390075Sobrien } 354132718Skan 355132718Skan return (1); 356132718Skan } 357132718Skan#endif 35896263Sobrien 35996263Sobrien if ((size_t)n >= sizeof(hdr.elf) && IS_ELF(hdr.elf) && 360132718Skan hdr.elf.e_ident[EI_CLASS] == ELF_TARG_CLASS) { 361132718Skan /* Handle default ELF objects on this architecture */ 36296263Sobrien Elf_Phdr phdr; 36396263Sobrien int dynamic, i; 36490075Sobrien 36596263Sobrien dynamic = 0; 36696263Sobrien *type = TYPE_ELF; 36796263Sobrien 36896263Sobrien if (lseek(fd, hdr.elf.e_phoff, SEEK_SET) == -1) { 36996263Sobrien warnx("%s: header too short", fname); 37090075Sobrien return (0); 371132718Skan } 37290075Sobrien for (i = 0; i < hdr.elf.e_phnum; i++) { 37390075Sobrien if (read(fd, &phdr, hdr.elf.e_phentsize) 37490075Sobrien != sizeof(phdr)) { 37590075Sobrien warnx("%s: can't read program header", fname); 37690075Sobrien return (0); 37790075Sobrien } 37890075Sobrien if (phdr.p_type == PT_DYNAMIC) { 379132718Skan dynamic = 1; 380117395Skan break; 381117395Skan } 382117395Skan } 383117395Skan 384117395Skan if (!dynamic) { 38590075Sobrien warnx("%s: not a dynamic ELF executable", fname); 38690075Sobrien return (0); 38790075Sobrien } 38890075Sobrien if (hdr.elf.e_type == ET_DYN) { 389132718Skan switch (hdr.elf.e_ident[EI_OSABI]) { 390132718Skan case ELFOSABI_FREEBSD: 391132718Skan *is_shlib = 1; 392132718Skan return (1); 393132718Skan#ifdef __ARM_EABI__ 394132718Skan case ELFOSABI_NONE: 395132718Skan if (hdr.elf.e_machine != EM_ARM) 396132718Skan break; 397132718Skan if (EF_ARM_EABI_VERSION(hdr.elf.e_flags) < 39890075Sobrien EF_ARM_EABI_FREEBSD_MIN) 39990075Sobrien break; 40090075Sobrien *is_shlib = 1; 40190075Sobrien return (1); 40290075Sobrien#endif 40390075Sobrien } 40490075Sobrien warnx("%s: not a FreeBSD ELF shared object", fname); 40590075Sobrien return (0); 40690075Sobrien } 40790075Sobrien 40890075Sobrien return (1); 409117395Skan } 41090075Sobrien 41190075Sobrien warnx("%s: not a dynamic executable", fname); 41290075Sobrien return (0); 413132718Skan} 41490075Sobrien