1330449Seadler/*- 2330449Seadler * SPDX-License-Identifier: BSD-4-Clause 3330449Seadler * 4696Spaul * Copyright (c) 1993 Paul Kranenburg 5696Spaul * All rights reserved. 6696Spaul * 7696Spaul * Redistribution and use in source and binary forms, with or without 8696Spaul * modification, are permitted provided that the following conditions 9696Spaul * are met: 10696Spaul * 1. Redistributions of source code must retain the above copyright 11696Spaul * notice, this list of conditions and the following disclaimer. 12696Spaul * 2. Redistributions in binary form must reproduce the above copyright 13696Spaul * notice, this list of conditions and the following disclaimer in the 14696Spaul * documentation and/or other materials provided with the distribution. 15696Spaul * 3. All advertising materials mentioning features or use of this software 16696Spaul * must display the following acknowledgement: 17696Spaul * This product includes software developed by Paul Kranenburg. 18696Spaul * 4. The name of the author may not be used to endorse or promote products 191153Sjkh * derived from this software without specific prior written permission 20696Spaul * 21696Spaul * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22696Spaul * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23696Spaul * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24696Spaul * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25696Spaul * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26696Spaul * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27696Spaul * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28696Spaul * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29696Spaul * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30696Spaul * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31696Spaul */ 32696Spaul 3395648Smarkm#include <sys/cdefs.h> 3495648Smarkm__FBSDID("$FreeBSD: stable/11/usr.bin/ldd/ldd.c 362427 2020-06-20 04:41:04Z kib $"); 3569827Scharnier 36696Spaul#include <sys/wait.h> 3795648Smarkm 3876224Sobrien#include <machine/elf.h> 3995648Smarkm 4095153Smike#include <arpa/inet.h> 4195648Smarkm 4290172Ssobomax#include <dlfcn.h> 431741Srich#include <err.h> 44180236Sedwin#include <errno.h> 451741Srich#include <fcntl.h> 461741Srich#include <stdio.h> 471741Srich#include <stdlib.h> 48181136Sjhb#include <string.h> 491741Srich#include <unistd.h> 50696Spaul 5195648Smarkm#include "extern.h" 5218600Speter 53294665Sbr/* We don't support a.out executables on arm64 and riscv */ 54294665Sbr#if !defined(__aarch64__) && !defined(__riscv__) 55280220Sandrew#include <a.out.h> 56280220Sandrew#define AOUT_SUPPORTED 57280220Sandrew#endif 58280220Sandrew 59180646Sedwin/* 60180877Sedwin * 32-bit ELF data structures can only be used if the system header[s] declare 61180877Sedwin * them. There is no official macro for determining whether they are declared, 62180877Sedwin * so check for the existence of one of the 32-macros defined in elf(5). 63180646Sedwin */ 64180877Sedwin#ifdef ELF32_R_TYPE 65180877Sedwin#define ELF32_SUPPORTED 66180646Sedwin#endif 67180646Sedwin 68254018Smarkj#define LDD_SETENV(name, value, overwrite) do { \ 69254018Smarkj setenv("LD_" name, value, overwrite); \ 70254018Smarkj setenv("LD_32_" name, value, overwrite); \ 71254018Smarkj} while (0) 72254018Smarkj 73254018Smarkj#define LDD_UNSETENV(name) do { \ 74254018Smarkj unsetenv("LD_" name); \ 75254018Smarkj unsetenv("LD_32_" name); \ 76254018Smarkj} while (0) 77254018Smarkj 78180235Sedwinstatic int is_executable(const char *fname, int fd, int *is_shlib, 79180235Sedwin int *type); 80180235Sedwinstatic void usage(void); 81180234Sedwin 82180235Sedwin#define TYPE_UNKNOWN 0 83180235Sedwin#define TYPE_AOUT 1 84180235Sedwin#define TYPE_ELF 2 /* Architecture default */ 85180646Sedwin#if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED) 86180236Sedwin#define TYPE_ELF32 3 /* Explicit 32 bits on architectures >32 bits */ 87696Spaul 88181136Sjhb#define _PATH_LDD32 "/usr/bin/ldd32" 89180235Sedwin 90181136Sjhbstatic int 91181136Sjhbexecldd32(char *file, char *fmt1, char *fmt2, int aflag, int vflag) 92181136Sjhb{ 93299952Struckman char *argv[9]; 94181136Sjhb int i, rval, status; 95181136Sjhb 96254018Smarkj LDD_UNSETENV("TRACE_LOADED_OBJECTS"); 97181136Sjhb rval = 0; 98181136Sjhb i = 0; 99181136Sjhb argv[i++] = strdup(_PATH_LDD32); 100181136Sjhb if (aflag) 101181136Sjhb argv[i++] = strdup("-a"); 102181136Sjhb if (vflag) 103181136Sjhb argv[i++] = strdup("-v"); 104181161Sjhb if (fmt1 != NULL) { 105181136Sjhb argv[i++] = strdup("-f"); 106181136Sjhb argv[i++] = strdup(fmt1); 107181136Sjhb } 108181161Sjhb if (fmt2 != NULL) { 109181136Sjhb argv[i++] = strdup("-f"); 110181136Sjhb argv[i++] = strdup(fmt2); 111181136Sjhb } 112181136Sjhb argv[i++] = strdup(file); 113181136Sjhb argv[i++] = NULL; 114181136Sjhb 115181136Sjhb switch (fork()) { 116181136Sjhb case -1: 117181136Sjhb err(1, "fork"); 118181136Sjhb break; 119181136Sjhb case 0: 120181136Sjhb execv(_PATH_LDD32, argv); 121181136Sjhb warn("%s", _PATH_LDD32); 122181161Sjhb _exit(127); 123181136Sjhb break; 124181136Sjhb default: 125181161Sjhb if (wait(&status) < 0) 126181136Sjhb rval = 1; 127181161Sjhb else if (WIFSIGNALED(status)) 128181136Sjhb rval = 1; 129181161Sjhb else if (WIFEXITED(status) && WEXITSTATUS(status) != 0) 130181136Sjhb rval = 1; 131181136Sjhb break; 132181136Sjhb } 133181136Sjhb while (i--) 134181136Sjhb free(argv[i]); 135254018Smarkj LDD_SETENV("TRACE_LOADED_OBJECTS", "yes", 1); 136181136Sjhb return (rval); 137181136Sjhb} 138180236Sedwin#endif 139180235Sedwin 140696Spaulint 14195648Smarkmmain(int argc, char *argv[]) 142696Spaul{ 143180234Sedwin char *fmt1, *fmt2; 144180234Sedwin int rval, c, aflag, vflag; 145696Spaul 14690755Sobrien aflag = vflag = 0; 147180234Sedwin fmt1 = fmt2 = NULL; 14890755Sobrien 149180234Sedwin while ((c = getopt(argc, argv, "af:v")) != -1) { 150696Spaul switch (c) { 15190755Sobrien case 'a': 15290755Sobrien aflag++; 15390755Sobrien break; 15418598Speter case 'f': 155180234Sedwin if (fmt1 != NULL) { 156180234Sedwin if (fmt2 != NULL) 15769827Scharnier errx(1, "too many formats"); 15818598Speter fmt2 = optarg; 15918598Speter } else 16018598Speter fmt1 = optarg; 16118598Speter break; 162180234Sedwin case 'v': 163180234Sedwin vflag++; 164180234Sedwin break; 165696Spaul default: 166696Spaul usage(); 167180234Sedwin /* NOTREACHED */ 168696Spaul } 169696Spaul } 170696Spaul argc -= optind; 171696Spaul argv += optind; 172696Spaul 173180234Sedwin if (vflag && fmt1 != NULL) 17418600Speter errx(1, "-v may not be used with -f"); 17518600Speter 176696Spaul if (argc <= 0) { 177696Spaul usage(); 178180234Sedwin /* NOTREACHED */ 179696Spaul } 180696Spaul 18139354Sdfr#ifdef __i386__ 18218600Speter if (vflag) { 18318600Speter for (c = 0; c < argc; c++) 18418600Speter dump_file(argv[c]); 18518600Speter exit(error_count == 0 ? EXIT_SUCCESS : EXIT_FAILURE); 18618600Speter } 18739354Sdfr#endif 18818600Speter 1891741Srich rval = 0; 190180234Sedwin for (; argc > 0; argc--, argv++) { 191180235Sedwin int fd, status, is_shlib, rv, type; 192696Spaul 193696Spaul if ((fd = open(*argv, O_RDONLY, 0)) < 0) { 1941741Srich warn("%s", *argv); 195696Spaul rval |= 1; 196696Spaul continue; 197696Spaul } 198180235Sedwin rv = is_executable(*argv, fd, &is_shlib, &type); 199180235Sedwin close(fd); 200180235Sedwin if (rv == 0) { 201696Spaul rval |= 1; 202696Spaul continue; 203696Spaul } 20435575Sdfr 205180236Sedwin switch (type) { 206180236Sedwin case TYPE_ELF: 207180236Sedwin case TYPE_AOUT: 208180236Sedwin break; 209180646Sedwin#if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED) 210180236Sedwin case TYPE_ELF32: 211181136Sjhb rval |= execldd32(*argv, fmt1, fmt2, aflag, vflag); 212181136Sjhb continue; 213180236Sedwin#endif 214180236Sedwin case TYPE_UNKNOWN: 215180236Sedwin default: 216180236Sedwin /* 217180236Sedwin * This shouldn't happen unless is_executable() 218180236Sedwin * is broken. 219180236Sedwin */ 220180236Sedwin errx(EDOOFUS, "unknown executable type"); 221180236Sedwin } 222180236Sedwin 223180235Sedwin /* ld.so magic */ 224254018Smarkj LDD_SETENV("TRACE_LOADED_OBJECTS", "yes", 1); 225180235Sedwin if (fmt1 != NULL) 226254018Smarkj LDD_SETENV("TRACE_LOADED_OBJECTS_FMT1", fmt1, 1); 227180235Sedwin if (fmt2 != NULL) 228254018Smarkj LDD_SETENV("TRACE_LOADED_OBJECTS_FMT2", fmt2, 1); 22935575Sdfr 230254018Smarkj LDD_SETENV("TRACE_LOADED_OBJECTS_PROGNAME", *argv, 1); 231180234Sedwin if (aflag) 232254018Smarkj LDD_SETENV("TRACE_LOADED_OBJECTS_ALL", "1", 1); 23390755Sobrien else if (fmt1 == NULL && fmt2 == NULL) 23418598Speter /* Default formats */ 23518598Speter printf("%s:\n", *argv); 2361153Sjkh fflush(stdout); 237696Spaul 238696Spaul switch (fork()) { 239696Spaul case -1: 2401741Srich err(1, "fork"); 241696Spaul break; 242696Spaul default: 243181161Sjhb if (wait(&status) < 0) { 2441741Srich warn("wait"); 2451741Srich rval |= 1; 2461741Srich } else if (WIFSIGNALED(status)) { 247180234Sedwin fprintf(stderr, "%s: signal %d\n", *argv, 248180234Sedwin WTERMSIG(status)); 249696Spaul rval |= 1; 250181161Sjhb } else if (WIFEXITED(status) && 251181161Sjhb WEXITSTATUS(status) != 0) { 252180234Sedwin fprintf(stderr, "%s: exit status %d\n", *argv, 253180234Sedwin WEXITSTATUS(status)); 254696Spaul rval |= 1; 255696Spaul } 256696Spaul break; 257696Spaul case 0: 258105439Ssobomax if (is_shlib == 0) { 25990172Ssobomax execl(*argv, *argv, (char *)NULL); 26090172Ssobomax warn("%s", *argv); 261105439Ssobomax } else { 262105439Ssobomax dlopen(*argv, RTLD_TRACE); 263105439Ssobomax warnx("%s: %s", *argv, dlerror()); 26490172Ssobomax } 265696Spaul _exit(1); 266696Spaul } 267696Spaul } 268696Spaul 269696Spaul return rval; 270696Spaul} 271180235Sedwin 272180235Sedwinstatic void 273180235Sedwinusage(void) 274180235Sedwin{ 275180235Sedwin 276180235Sedwin fprintf(stderr, "usage: ldd [-a] [-v] [-f format] program ...\n"); 277180235Sedwin exit(1); 278180235Sedwin} 279180235Sedwin 280180235Sedwinstatic int 281180235Sedwinis_executable(const char *fname, int fd, int *is_shlib, int *type) 282180235Sedwin{ 283180235Sedwin union { 284280220Sandrew#ifdef AOUT_SUPPORTED 285180235Sedwin struct exec aout; 286280220Sandrew#endif 287180646Sedwin#if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED) 288180236Sedwin Elf32_Ehdr elf32; 289180646Sedwin#endif 290180235Sedwin Elf_Ehdr elf; 291180235Sedwin } hdr; 292362427Skib Elf_Phdr phdr, dynphdr; 293362427Skib Elf_Dyn *dynp; 294362427Skib void *dyndata; 295362427Skib#if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED) 296362427Skib Elf32_Phdr phdr32, dynphdr32; 297362427Skib Elf32_Dyn *dynp32; 298362427Skib#endif 299362427Skib int df1pie, dynamic, i, n; 300180235Sedwin 301180235Sedwin *is_shlib = 0; 302180235Sedwin *type = TYPE_UNKNOWN; 303362427Skib df1pie = 0; 304180235Sedwin 305180235Sedwin if ((n = read(fd, &hdr, sizeof(hdr))) == -1) { 306180235Sedwin warn("%s: can't read program header", fname); 307180235Sedwin return (0); 308180235Sedwin } 309180235Sedwin 310280220Sandrew#ifdef AOUT_SUPPORTED 311180235Sedwin if ((size_t)n >= sizeof(hdr.aout) && !N_BADMAG(hdr.aout)) { 312180235Sedwin /* a.out file */ 313180235Sedwin if ((N_GETFLAG(hdr.aout) & EX_DPMASK) != EX_DYNAMIC 314180235Sedwin#if 1 /* Compatibility */ 315180235Sedwin || hdr.aout.a_entry < __LDPGSZ 316180235Sedwin#endif 317180235Sedwin ) { 318180235Sedwin warnx("%s: not a dynamic executable", fname); 319180235Sedwin return (0); 320180235Sedwin } 321180235Sedwin *type = TYPE_AOUT; 322180235Sedwin return (1); 323180235Sedwin } 324280220Sandrew#endif 325180235Sedwin 326180646Sedwin#if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED) 327180236Sedwin if ((size_t)n >= sizeof(hdr.elf32) && IS_ELF(hdr.elf32) && 328180236Sedwin hdr.elf32.e_ident[EI_CLASS] == ELFCLASS32) { 329180236Sedwin /* Handle 32 bit ELF objects */ 330180236Sedwin 331180236Sedwin dynamic = 0; 332180236Sedwin *type = TYPE_ELF32; 333180236Sedwin 334180236Sedwin if (lseek(fd, hdr.elf32.e_phoff, SEEK_SET) == -1) { 335180236Sedwin warnx("%s: header too short", fname); 336180236Sedwin return (0); 337180236Sedwin } 338180236Sedwin for (i = 0; i < hdr.elf32.e_phnum; i++) { 339362427Skib if (read(fd, &phdr32, hdr.elf32.e_phentsize) != 340362427Skib sizeof(phdr32)) { 341180236Sedwin warnx("%s: can't read program header", fname); 342180236Sedwin return (0); 343180236Sedwin } 344362427Skib if (phdr32.p_type == PT_DYNAMIC) { 345180236Sedwin dynamic = 1; 346362427Skib dynphdr32 = phdr32; 347180236Sedwin break; 348180236Sedwin } 349180236Sedwin } 350180236Sedwin 351180236Sedwin if (!dynamic) { 352180236Sedwin warnx("%s: not a dynamic ELF executable", fname); 353180236Sedwin return (0); 354180236Sedwin } 355362427Skib 356180236Sedwin if (hdr.elf32.e_type == ET_DYN) { 357362427Skib if (lseek(fd, dynphdr32.p_offset, SEEK_SET) == -1) { 358362427Skib warnx("%s: dynamic segment out of range", 359362427Skib fname); 360362427Skib return (0); 361362427Skib } 362362427Skib dyndata = malloc(dynphdr32.p_filesz); 363362427Skib if (dyndata == NULL) { 364362427Skib warn("malloc"); 365362427Skib return (0); 366362427Skib } 367362427Skib if (read(fd, dyndata, dynphdr32.p_filesz) != 368362427Skib (ssize_t)dynphdr32.p_filesz) { 369362427Skib free(dyndata); 370362427Skib warnx("%s: can't read dynamic segment", fname); 371362427Skib return (0); 372362427Skib } 373362427Skib for (dynp32 = dyndata; dynp32->d_tag != DT_NULL; 374362427Skib dynp32++) { 375362427Skib if (dynp32->d_tag != DT_FLAGS_1) 376362427Skib continue; 377362427Skib df1pie = (dynp32->d_un.d_val & DF_1_PIE) != 0; 378362427Skib break; 379362427Skib } 380362427Skib free(dyndata); 381362427Skib 382215705Sbrucec if (hdr.elf32.e_ident[EI_OSABI] == ELFOSABI_FREEBSD) { 383362427Skib if (!df1pie) 384362427Skib *is_shlib = 1; 385180236Sedwin return (1); 386180236Sedwin } 387180236Sedwin warnx("%s: not a FreeBSD ELF shared object", fname); 388180236Sedwin return (0); 389180236Sedwin } 390180236Sedwin 391180236Sedwin return (1); 392180236Sedwin } 393180236Sedwin#endif 394180236Sedwin 395180235Sedwin if ((size_t)n >= sizeof(hdr.elf) && IS_ELF(hdr.elf) && 396180235Sedwin hdr.elf.e_ident[EI_CLASS] == ELF_TARG_CLASS) { 397180235Sedwin /* Handle default ELF objects on this architecture */ 398180235Sedwin 399180235Sedwin dynamic = 0; 400180235Sedwin *type = TYPE_ELF; 401180235Sedwin 402180235Sedwin if (lseek(fd, hdr.elf.e_phoff, SEEK_SET) == -1) { 403180235Sedwin warnx("%s: header too short", fname); 404180235Sedwin return (0); 405180235Sedwin } 406180235Sedwin for (i = 0; i < hdr.elf.e_phnum; i++) { 407180235Sedwin if (read(fd, &phdr, hdr.elf.e_phentsize) 408180235Sedwin != sizeof(phdr)) { 409180235Sedwin warnx("%s: can't read program header", fname); 410180235Sedwin return (0); 411180235Sedwin } 412180235Sedwin if (phdr.p_type == PT_DYNAMIC) { 413180235Sedwin dynamic = 1; 414362427Skib dynphdr = phdr; 415180235Sedwin break; 416180235Sedwin } 417180235Sedwin } 418180235Sedwin 419180235Sedwin if (!dynamic) { 420180235Sedwin warnx("%s: not a dynamic ELF executable", fname); 421180235Sedwin return (0); 422180235Sedwin } 423362427Skib 424180235Sedwin if (hdr.elf.e_type == ET_DYN) { 425362427Skib if (lseek(fd, dynphdr.p_offset, SEEK_SET) == -1) { 426362427Skib warnx("%s: dynamic segment out of range", 427362427Skib fname); 428362427Skib return (0); 429362427Skib } 430362427Skib dyndata = malloc(dynphdr.p_filesz); 431362427Skib if (dyndata == NULL) { 432362427Skib warn("malloc"); 433362427Skib return (0); 434362427Skib } 435362427Skib if (read(fd, dyndata, dynphdr.p_filesz) != 436362427Skib (ssize_t)dynphdr.p_filesz) { 437362427Skib free(dyndata); 438362427Skib warnx("%s: can't read dynamic segment", fname); 439362427Skib return (0); 440362427Skib } 441362427Skib for (dynp = dyndata; dynp->d_tag != DT_NULL; dynp++) { 442362427Skib if (dynp->d_tag != DT_FLAGS_1) 443362427Skib continue; 444362427Skib df1pie = (dynp->d_un.d_val & DF_1_PIE) != 0; 445362427Skib break; 446362427Skib } 447362427Skib free(dyndata); 448362427Skib 449289425Sjkim switch (hdr.elf.e_ident[EI_OSABI]) { 450289425Sjkim case ELFOSABI_FREEBSD: 451362427Skib if (!df1pie) 452362427Skib *is_shlib = 1; 453180235Sedwin return (1); 454289425Sjkim#ifdef __ARM_EABI__ 455289425Sjkim case ELFOSABI_NONE: 456289425Sjkim if (hdr.elf.e_machine != EM_ARM) 457289425Sjkim break; 458289425Sjkim if (EF_ARM_EABI_VERSION(hdr.elf.e_flags) < 459289425Sjkim EF_ARM_EABI_FREEBSD_MIN) 460289425Sjkim break; 461289425Sjkim *is_shlib = 1; 462289425Sjkim return (1); 463289425Sjkim#endif 464180235Sedwin } 465180235Sedwin warnx("%s: not a FreeBSD ELF shared object", fname); 466180235Sedwin return (0); 467180235Sedwin } 468180235Sedwin 469180235Sedwin return (1); 470180235Sedwin } 471180235Sedwin 472180235Sedwin warnx("%s: not a dynamic executable", fname); 473180235Sedwin return (0); 474180235Sedwin} 475