11618Srie /* 21618Srie * CDDL HEADER START 31618Srie * 41618Srie * The contents of this file are subject to the terms of the 51618Srie * Common Development and Distribution License (the "License"). 61618Srie * You may not use this file except in compliance with the License. 71618Srie * 81618Srie * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 91618Srie * or http://www.opensolaris.org/os/licensing. 101618Srie * See the License for the specific language governing permissions 111618Srie * and limitations under the License. 121618Srie * 131618Srie * When distributing Covered Code, include this CDDL HEADER in each 141618Srie * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 151618Srie * If applicable, add the following below this CDDL HEADER, with the 161618Srie * fields enclosed by brackets "[]" replaced with your own identifying 171618Srie * information: Portions Copyright [yyyy] [name of copyright owner] 181618Srie * 191618Srie * CDDL HEADER END 201618Srie */ 211618Srie 221618Srie /* 23*6635Sab196087 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 241618Srie * Use is subject to license terms. 251618Srie */ 261618Srie #pragma ident "%Z%%M% %I% %E% SMI" 271618Srie 281618Srie /* 291618Srie * Dump an elf file. 301618Srie */ 311618Srie #include <sys/param.h> 321618Srie #include <fcntl.h> 331618Srie #include <stdio.h> 344168Sab196087 #include <stdlib.h> 354168Sab196087 #include <ctype.h> 361618Srie #include <libelf.h> 371618Srie #include <link.h> 381618Srie #include <stdarg.h> 391618Srie #include <unistd.h> 401618Srie #include <libgen.h> 411618Srie #include <libintl.h> 421618Srie #include <locale.h> 431618Srie #include <errno.h> 441618Srie #include <strings.h> 451618Srie #include <debug.h> 461618Srie #include <conv.h> 471618Srie #include <msg.h> 481618Srie #include <_elfdump.h> 495411Sab196087 #include <sys/elf_SPARC.h> 505411Sab196087 #include <sys/elf_amd64.h> 515411Sab196087 521618Srie 534063Sab196087 const Cache cache_init = {NULL, NULL, NULL, NULL, 0}; 541618Srie 554168Sab196087 564168Sab196087 575411Sab196087 /* 585411Sab196087 * The -I, -N, and -T options are called "match options", because 595411Sab196087 * they allow selecting the items to be displayed based on matching 605411Sab196087 * their index, name, or type. 615411Sab196087 * 625411Sab196087 * The ELF information to which -I, -N, or -T are applied in 635411Sab196087 * the current invocation is called the "match item". 645411Sab196087 */ 654168Sab196087 typedef enum { 665411Sab196087 MATCH_ITEM_PT, /* Program header (PT_) */ 675411Sab196087 MATCH_ITEM_SHT /* Section header (SHT_) */ 685411Sab196087 } match_item_t; 695411Sab196087 705411Sab196087 /* match_opt_t is used to note which match option was used */ 715411Sab196087 typedef enum { 725411Sab196087 MATCH_OPT_NAME, /* Record contains a name */ 735411Sab196087 MATCH_OPT_NDX, /* Record contains a single index */ 745411Sab196087 MATCH_OPT_RANGE, /* Record contains an index range */ 755411Sab196087 MATCH_OPT_TYPE, /* Record contains a type (shdr or phdr) */ 765411Sab196087 } match_opt_t; 774168Sab196087 784168Sab196087 typedef struct _match { 794168Sab196087 struct _match *next; /* Pointer to next item in list */ 805411Sab196087 match_opt_t opt_type; 814168Sab196087 union { 825411Sab196087 const char *name; /* MATCH_OPT_NAME */ 835411Sab196087 struct { /* MATCH_OPT_NDX and MATCH_OPT_RANGE */ 844168Sab196087 int start; 855411Sab196087 int end; /* Only for MATCH_OPT_RANGE */ 864168Sab196087 } ndx; 875411Sab196087 uint32_t type; /* MATCH_OPT_TYPE */ 884168Sab196087 } value; 895411Sab196087 } match_rec_t; 905411Sab196087 915411Sab196087 static struct { 925411Sab196087 match_item_t item_type; /* Type of item being matched */ 935411Sab196087 match_rec_t *list; /* Records for (-I, -N, -T) options */ 945411Sab196087 } match_state; 955411Sab196087 965411Sab196087 975411Sab196087 985411Sab196087 /* Map names to their integer value */ 995411Sab196087 typedef struct { 1005411Sab196087 const char *sym_name; 1015411Sab196087 uint32_t sym_value; 1025411Sab196087 } atoui_sym_t; 1035411Sab196087 1045411Sab196087 /* 1055411Sab196087 * ELF section types. 1065411Sab196087 */ 1075411Sab196087 static atoui_sym_t sym_sht[] = { 1085411Sab196087 { MSG_ORIG(MSG_SHT_NULL), SHT_NULL }, 1095411Sab196087 { MSG_ORIG(MSG_SHT_NULL_ALT1), SHT_NULL }, 1105411Sab196087 1115411Sab196087 { MSG_ORIG(MSG_SHT_PROGBITS), SHT_PROGBITS }, 1125411Sab196087 { MSG_ORIG(MSG_SHT_PROGBITS_ALT1), SHT_PROGBITS }, 1135411Sab196087 1145411Sab196087 { MSG_ORIG(MSG_SHT_SYMTAB), SHT_SYMTAB }, 1155411Sab196087 { MSG_ORIG(MSG_SHT_SYMTAB_ALT1), SHT_SYMTAB }, 1165411Sab196087 1175411Sab196087 { MSG_ORIG(MSG_SHT_STRTAB), SHT_STRTAB }, 1185411Sab196087 { MSG_ORIG(MSG_SHT_STRTAB_ALT1), SHT_STRTAB }, 1195411Sab196087 1205411Sab196087 { MSG_ORIG(MSG_SHT_RELA), SHT_RELA }, 1215411Sab196087 { MSG_ORIG(MSG_SHT_RELA_ALT1), SHT_RELA }, 1225411Sab196087 1235411Sab196087 { MSG_ORIG(MSG_SHT_HASH), SHT_HASH }, 1245411Sab196087 { MSG_ORIG(MSG_SHT_HASH_ALT1), SHT_HASH }, 1255411Sab196087 1265411Sab196087 { MSG_ORIG(MSG_SHT_DYNAMIC), SHT_DYNAMIC }, 1275411Sab196087 { MSG_ORIG(MSG_SHT_DYNAMIC_ALT1), SHT_DYNAMIC }, 1285411Sab196087 1295411Sab196087 { MSG_ORIG(MSG_SHT_NOTE), SHT_NOTE }, 1305411Sab196087 { MSG_ORIG(MSG_SHT_NOTE_ALT1), SHT_NOTE }, 1315411Sab196087 1325411Sab196087 { MSG_ORIG(MSG_SHT_NOBITS), SHT_NOBITS }, 1335411Sab196087 { MSG_ORIG(MSG_SHT_NOBITS_ALT1), SHT_NOBITS }, 1345411Sab196087 1355411Sab196087 { MSG_ORIG(MSG_SHT_REL), SHT_REL }, 1365411Sab196087 { MSG_ORIG(MSG_SHT_REL_ALT1), SHT_REL }, 1375411Sab196087 1385411Sab196087 { MSG_ORIG(MSG_SHT_SHLIB), SHT_SHLIB }, 1395411Sab196087 { MSG_ORIG(MSG_SHT_SHLIB_ALT1), SHT_SHLIB }, 1405411Sab196087 1415411Sab196087 { MSG_ORIG(MSG_SHT_DYNSYM), SHT_DYNSYM }, 1425411Sab196087 { MSG_ORIG(MSG_SHT_DYNSYM_ALT1), SHT_DYNSYM }, 1435411Sab196087 1445411Sab196087 { MSG_ORIG(MSG_SHT_INIT_ARRAY), SHT_INIT_ARRAY }, 1455411Sab196087 { MSG_ORIG(MSG_SHT_INIT_ARRAY_ALT1), SHT_INIT_ARRAY }, 1465411Sab196087 1475411Sab196087 { MSG_ORIG(MSG_SHT_FINI_ARRAY), SHT_FINI_ARRAY }, 1485411Sab196087 { MSG_ORIG(MSG_SHT_FINI_ARRAY_ALT1), SHT_FINI_ARRAY }, 1495411Sab196087 1505411Sab196087 { MSG_ORIG(MSG_SHT_PREINIT_ARRAY), SHT_PREINIT_ARRAY }, 1515411Sab196087 { MSG_ORIG(MSG_SHT_PREINIT_ARRAY_ALT1), SHT_PREINIT_ARRAY }, 1525411Sab196087 1535411Sab196087 { MSG_ORIG(MSG_SHT_GROUP), SHT_GROUP }, 1545411Sab196087 { MSG_ORIG(MSG_SHT_GROUP_ALT1), SHT_GROUP }, 1555411Sab196087 1565411Sab196087 { MSG_ORIG(MSG_SHT_SYMTAB_SHNDX), SHT_SYMTAB_SHNDX }, 1575411Sab196087 { MSG_ORIG(MSG_SHT_SYMTAB_SHNDX_ALT1), SHT_SYMTAB_SHNDX }, 1585411Sab196087 1595411Sab196087 { MSG_ORIG(MSG_SHT_SUNW_SYMSORT), SHT_SUNW_symsort }, 1605411Sab196087 { MSG_ORIG(MSG_SHT_SUNW_SYMSORT_ALT1), SHT_SUNW_symsort }, 1615411Sab196087 1625411Sab196087 { MSG_ORIG(MSG_SHT_SUNW_TLSSORT), SHT_SUNW_tlssort }, 1635411Sab196087 { MSG_ORIG(MSG_SHT_SUNW_TLSSORT_ALT1), SHT_SUNW_tlssort }, 1645411Sab196087 1655411Sab196087 { MSG_ORIG(MSG_SHT_SUNW_LDYNSYM), SHT_SUNW_LDYNSYM }, 1665411Sab196087 { MSG_ORIG(MSG_SHT_SUNW_LDYNSYM_ALT1), SHT_SUNW_LDYNSYM }, 1675411Sab196087 1685411Sab196087 { MSG_ORIG(MSG_SHT_SUNW_DOF), SHT_SUNW_dof }, 1695411Sab196087 { MSG_ORIG(MSG_SHT_SUNW_DOF_ALT1), SHT_SUNW_dof }, 1705411Sab196087 1715411Sab196087 { MSG_ORIG(MSG_SHT_SUNW_CAP), SHT_SUNW_cap }, 1725411Sab196087 { MSG_ORIG(MSG_SHT_SUNW_CAP_ALT1), SHT_SUNW_cap }, 1735411Sab196087 1745411Sab196087 { MSG_ORIG(MSG_SHT_SUNW_SIGNATURE), SHT_SUNW_SIGNATURE }, 1755411Sab196087 { MSG_ORIG(MSG_SHT_SUNW_SIGNATURE_ALT1), SHT_SUNW_SIGNATURE }, 1765411Sab196087 1775411Sab196087 { MSG_ORIG(MSG_SHT_SUNW_ANNOTATE), SHT_SUNW_ANNOTATE }, 1785411Sab196087 { MSG_ORIG(MSG_SHT_SUNW_ANNOTATE_ALT1), SHT_SUNW_ANNOTATE }, 1794168Sab196087 1805411Sab196087 { MSG_ORIG(MSG_SHT_SUNW_DEBUGSTR), SHT_SUNW_DEBUGSTR }, 1815411Sab196087 { MSG_ORIG(MSG_SHT_SUNW_DEBUGSTR_ALT1), SHT_SUNW_DEBUGSTR }, 1825411Sab196087 1835411Sab196087 { MSG_ORIG(MSG_SHT_SUNW_DEBUG), SHT_SUNW_DEBUG }, 1845411Sab196087 { MSG_ORIG(MSG_SHT_SUNW_DEBUG_ALT1), SHT_SUNW_DEBUG }, 1855411Sab196087 1865411Sab196087 { MSG_ORIG(MSG_SHT_SUNW_MOVE), SHT_SUNW_move }, 1875411Sab196087 { MSG_ORIG(MSG_SHT_SUNW_MOVE_ALT1), SHT_SUNW_move }, 1885411Sab196087 1895411Sab196087 { MSG_ORIG(MSG_SHT_SUNW_COMDAT), SHT_SUNW_COMDAT }, 1905411Sab196087 { MSG_ORIG(MSG_SHT_SUNW_COMDAT_ALT1), SHT_SUNW_COMDAT }, 1915411Sab196087 1925411Sab196087 { MSG_ORIG(MSG_SHT_SUNW_SYMINFO), SHT_SUNW_syminfo }, 1935411Sab196087 { MSG_ORIG(MSG_SHT_SUNW_SYMINFO_ALT1), SHT_SUNW_syminfo }, 1945411Sab196087 1955411Sab196087 { MSG_ORIG(MSG_SHT_SUNW_VERDEF), SHT_SUNW_verdef }, 1965411Sab196087 { MSG_ORIG(MSG_SHT_SUNW_VERDEF_ALT1), SHT_SUNW_verdef }, 1975411Sab196087 1985411Sab196087 { MSG_ORIG(MSG_SHT_GNU_VERDEF), SHT_GNU_verdef }, 1995411Sab196087 { MSG_ORIG(MSG_SHT_GNU_VERDEF_ALT1), SHT_GNU_verdef }, 2005411Sab196087 2015411Sab196087 { MSG_ORIG(MSG_SHT_SUNW_VERNEED), SHT_SUNW_verneed }, 2025411Sab196087 { MSG_ORIG(MSG_SHT_SUNW_VERNEED_ALT1), SHT_SUNW_verneed }, 2035411Sab196087 2045411Sab196087 { MSG_ORIG(MSG_SHT_GNU_VERNEED), SHT_GNU_verneed }, 2055411Sab196087 { MSG_ORIG(MSG_SHT_GNU_VERNEED_ALT1), SHT_GNU_verneed }, 2065411Sab196087 2075411Sab196087 { MSG_ORIG(MSG_SHT_SUNW_VERSYM), SHT_SUNW_versym }, 2085411Sab196087 { MSG_ORIG(MSG_SHT_SUNW_VERSYM_ALT1), SHT_SUNW_versym }, 2095411Sab196087 2105411Sab196087 { MSG_ORIG(MSG_SHT_GNU_VERSYM), SHT_GNU_versym }, 2115411Sab196087 { MSG_ORIG(MSG_SHT_GNU_VERSYM_ALT1), SHT_GNU_versym }, 2125411Sab196087 2135411Sab196087 { MSG_ORIG(MSG_SHT_SPARC_GOTDATA), SHT_SPARC_GOTDATA }, 2145411Sab196087 { MSG_ORIG(MSG_SHT_SPARC_GOTDATA_ALT1), SHT_SPARC_GOTDATA }, 2155411Sab196087 2165411Sab196087 { MSG_ORIG(MSG_SHT_AMD64_UNWIND), SHT_AMD64_UNWIND }, 2175411Sab196087 { MSG_ORIG(MSG_SHT_AMD64_UNWIND_ALT1), SHT_AMD64_UNWIND }, 2185411Sab196087 2195411Sab196087 { NULL } 2205411Sab196087 }; 2215411Sab196087 2225411Sab196087 /* 2235411Sab196087 * Program header PT_* type values 2245411Sab196087 */ 2255411Sab196087 static atoui_sym_t sym_pt[] = { 2265411Sab196087 { MSG_ORIG(MSG_PT_NULL), PT_NULL }, 2275411Sab196087 { MSG_ORIG(MSG_PT_NULL_ALT1), PT_NULL }, 2285411Sab196087 2295411Sab196087 { MSG_ORIG(MSG_PT_LOAD), PT_LOAD }, 2305411Sab196087 { MSG_ORIG(MSG_PT_LOAD_ALT1), PT_LOAD }, 2315411Sab196087 2325411Sab196087 { MSG_ORIG(MSG_PT_DYNAMIC), PT_DYNAMIC }, 2335411Sab196087 { MSG_ORIG(MSG_PT_DYNAMIC_ALT1), PT_DYNAMIC }, 2345411Sab196087 2355411Sab196087 { MSG_ORIG(MSG_PT_INTERP), PT_INTERP }, 2365411Sab196087 { MSG_ORIG(MSG_PT_INTERP_ALT1), PT_INTERP }, 2375411Sab196087 2385411Sab196087 { MSG_ORIG(MSG_PT_NOTE), PT_NOTE }, 2395411Sab196087 { MSG_ORIG(MSG_PT_NOTE_ALT1), PT_NOTE }, 2405411Sab196087 2415411Sab196087 { MSG_ORIG(MSG_PT_SHLIB), PT_SHLIB }, 2425411Sab196087 { MSG_ORIG(MSG_PT_SHLIB_ALT1), PT_SHLIB }, 2435411Sab196087 2445411Sab196087 { MSG_ORIG(MSG_PT_PHDR), PT_PHDR }, 2455411Sab196087 { MSG_ORIG(MSG_PT_PHDR_ALT1), PT_PHDR }, 2465411Sab196087 2475411Sab196087 { MSG_ORIG(MSG_PT_TLS), PT_TLS }, 2485411Sab196087 { MSG_ORIG(MSG_PT_TLS_ALT1), PT_TLS }, 2495411Sab196087 2505411Sab196087 { MSG_ORIG(MSG_PT_SUNW_UNWIND), PT_SUNW_UNWIND }, 2515411Sab196087 { MSG_ORIG(MSG_PT_SUNW_UNWIND_ALT1), PT_SUNW_UNWIND }, 2525411Sab196087 2535411Sab196087 { MSG_ORIG(MSG_PT_SUNWBSS), PT_SUNWBSS }, 2545411Sab196087 { MSG_ORIG(MSG_PT_SUNWBSS_ALT1), PT_SUNWBSS }, 2555411Sab196087 2565411Sab196087 { MSG_ORIG(MSG_PT_SUNWSTACK), PT_SUNWSTACK }, 2575411Sab196087 { MSG_ORIG(MSG_PT_SUNWSTACK_ALT1), PT_SUNWSTACK }, 2585411Sab196087 2595411Sab196087 { MSG_ORIG(MSG_PT_SUNWDTRACE), PT_SUNWDTRACE }, 2605411Sab196087 { MSG_ORIG(MSG_PT_SUNWDTRACE_ALT1), PT_SUNWDTRACE }, 2615411Sab196087 2625411Sab196087 { MSG_ORIG(MSG_PT_SUNWCAP), PT_SUNWCAP }, 2635411Sab196087 { MSG_ORIG(MSG_PT_SUNWCAP_ALT1), PT_SUNWCAP }, 2645411Sab196087 2655411Sab196087 { NULL } 2665411Sab196087 }; 2675411Sab196087 2685411Sab196087 2695411Sab196087 2705411Sab196087 2714168Sab196087 2721618Srie const char * 2731618Srie _elfdump_msg(Msg mid) 2741618Srie { 2751618Srie return (gettext(MSG_ORIG(mid))); 2761618Srie } 2771618Srie 2781618Srie /* 2791618Srie * Determine whether a symbol name should be demangled. 2801618Srie */ 2811618Srie const char * 2821618Srie demangle(const char *name, uint_t flags) 2831618Srie { 2845411Sab196087 if (flags & FLG_CTL_DEMANGLE) 2851618Srie return (Elf_demangle_name(name)); 2861618Srie else 2871618Srie return ((char *)name); 2881618Srie } 2891618Srie 2901618Srie /* 2911618Srie * Define our own standard error routine. 2921618Srie */ 2931618Srie void 2941618Srie failure(const char *file, const char *func) 2951618Srie { 2961618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_FAILURE), 2971618Srie file, func, elf_errmsg(elf_errno())); 2981618Srie } 2991618Srie 3001618Srie /* 3011618Srie * The full usage message 3021618Srie */ 3031618Srie static void 3041618Srie detail_usage() 3051618Srie { 3061618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL1)); 3071618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL2)); 3081618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL3)); 3091618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL4)); 3101618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL5)); 3111618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL6)); 3121618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL7)); 3131618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL8)); 3141618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL9)); 3151618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL10)); 3161618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL11)); 3171618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL12)); 3181618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL13)); 3191618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL14)); 3201618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL15)); 3211618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL16)); 3221618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL17)); 3231618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL18)); 3241618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL19)); 3251618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL20)); 3263492Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL21)); 3274168Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL22)); 3284168Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL23)); 3294665Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL24)); 3305411Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL25)); 3314168Sab196087 } 3324168Sab196087 3334168Sab196087 /* 334*6635Sab196087 * Output a block of raw data as hex bytes. Each row is given 335*6635Sab196087 * the index of the first byte in the row. 336*6635Sab196087 * 337*6635Sab196087 * entry: 338*6635Sab196087 * data - Pointer to first byte of data to be displayed 339*6635Sab196087 * n - # of bytes of data 340*6635Sab196087 * prefix - String to be output before each line. Useful 341*6635Sab196087 * for indenting output. 342*6635Sab196087 * bytes_per_col - # of space separated bytes to output 343*6635Sab196087 * in each column. 344*6635Sab196087 * col_per_row - # of columns to output per row 345*6635Sab196087 * 346*6635Sab196087 * exit: 347*6635Sab196087 * The formatted data has been sent to stdout. Each row of output 348*6635Sab196087 * shows (bytes_per_col * col_per_row) bytes of data. 349*6635Sab196087 */ 350*6635Sab196087 void 351*6635Sab196087 dump_hex_bytes(const char *data, size_t n, int indent, 352*6635Sab196087 int bytes_per_col, int col_per_row) 353*6635Sab196087 { 354*6635Sab196087 int bytes_per_row = bytes_per_col * col_per_row; 355*6635Sab196087 int ndx, byte, word; 356*6635Sab196087 char string[128], *str = string; 357*6635Sab196087 char index[MAXNDXSIZE]; 358*6635Sab196087 int index_width; 359*6635Sab196087 int sp_prefix = 0; 360*6635Sab196087 361*6635Sab196087 362*6635Sab196087 /* 363*6635Sab196087 * Determine the width to use for the index string. We follow 364*6635Sab196087 * 8-byte tab rules, but don't use an actual \t character so 365*6635Sab196087 * that the output can be arbitrarily shifted without odd 366*6635Sab196087 * tab effects, and so that all the columns line up no matter 367*6635Sab196087 * how many lines of output are produced. 368*6635Sab196087 */ 369*6635Sab196087 ndx = n / bytes_per_row; 370*6635Sab196087 (void) snprintf(index, sizeof (index), 371*6635Sab196087 MSG_ORIG(MSG_FMT_INDEX2), EC_WORD(ndx)); 372*6635Sab196087 index_width = strlen(index); 373*6635Sab196087 index_width = S_ROUND(index_width, 8); 374*6635Sab196087 375*6635Sab196087 for (ndx = byte = word = 0; n > 0; n--, data++) { 376*6635Sab196087 while (sp_prefix-- > 0) 377*6635Sab196087 *str++ = ' '; 378*6635Sab196087 379*6635Sab196087 (void) snprintf(str, sizeof (string), 380*6635Sab196087 MSG_ORIG(MSG_HEXDUMP_TOK), (int)*data); 381*6635Sab196087 str += 2; 382*6635Sab196087 sp_prefix = 1; 383*6635Sab196087 384*6635Sab196087 if (++byte == bytes_per_col) { 385*6635Sab196087 sp_prefix += 2; 386*6635Sab196087 word++; 387*6635Sab196087 byte = 0; 388*6635Sab196087 } 389*6635Sab196087 if (word == col_per_row) { 390*6635Sab196087 *str = '\0'; 391*6635Sab196087 (void) snprintf(index, sizeof (index), 392*6635Sab196087 MSG_ORIG(MSG_FMT_INDEX2), EC_WORD(ndx)); 393*6635Sab196087 dbg_print(0, MSG_ORIG(MSG_HEXDUMP_ROW), 394*6635Sab196087 indent, MSG_ORIG(MSG_STR_EMPTY), 395*6635Sab196087 index_width, index, string); 396*6635Sab196087 sp_prefix = 0; 397*6635Sab196087 word = 0; 398*6635Sab196087 ndx += bytes_per_row; 399*6635Sab196087 str = string; 400*6635Sab196087 } 401*6635Sab196087 } 402*6635Sab196087 if (byte || word) { 403*6635Sab196087 *str = '\0'; /* */ 404*6635Sab196087 (void) snprintf(index, sizeof (index), 405*6635Sab196087 MSG_ORIG(MSG_FMT_INDEX2), EC_WORD(ndx)); 406*6635Sab196087 dbg_print(0, MSG_ORIG(MSG_HEXDUMP_ROW), indent, 407*6635Sab196087 MSG_ORIG(MSG_STR_EMPTY), index_width, index, string); 408*6635Sab196087 } 409*6635Sab196087 } 410*6635Sab196087 411*6635Sab196087 /* 4124168Sab196087 * Convert the ASCII representation of an index, or index range, into 4134168Sab196087 * binary form, and store it in rec: 4144168Sab196087 * 4154168Sab196087 * index: An positive or 0 valued integer 4164168Sab196087 * range: Two indexes, separated by a ':' character, denoting 4174168Sab196087 * a range of allowed values. If the second value is omitted, 4184168Sab196087 * any values equal to or greater than the first will match. 4194168Sab196087 * 4204168Sab196087 * exit: 4215411Sab196087 * On success, *rec is filled in with a MATCH_OPT_NDX or MATCH_OPT_RANGE 4224168Sab196087 * value, and this function returns (1). On failure, the contents 4234168Sab196087 * of *rec are undefined, and (0) is returned. 4244168Sab196087 */ 4254168Sab196087 int 4265411Sab196087 process_index_opt(const char *str, match_rec_t *rec) 4274168Sab196087 { 4284168Sab196087 #define SKIP_BLANK for (; *str && isspace(*str); str++) 4294168Sab196087 4304168Sab196087 char *endptr; 4314168Sab196087 4324168Sab196087 rec->value.ndx.start = strtol(str, &endptr, 10); 4334168Sab196087 /* Value must use some of the input, and be 0 or positive */ 4344168Sab196087 if ((str == endptr) || (rec->value.ndx.start < 0)) 4354168Sab196087 return (0); 4364168Sab196087 str = endptr; 4374168Sab196087 4384168Sab196087 SKIP_BLANK; 4394168Sab196087 if (*str != ':') { 4405411Sab196087 rec->opt_type = MATCH_OPT_NDX; 4414168Sab196087 } else { 4424168Sab196087 str++; /* Skip the ':' */ 4435411Sab196087 rec->opt_type = MATCH_OPT_RANGE; 4444168Sab196087 SKIP_BLANK; 4454168Sab196087 if (*str == '\0') { 4464168Sab196087 rec->value.ndx.end = -1; /* Indicates "to end" */ 4474168Sab196087 } else { 4484168Sab196087 rec->value.ndx.end = strtol(str, &endptr, 10); 4494168Sab196087 if ((str == endptr) || (rec->value.ndx.end < 0)) 4504168Sab196087 return (0); 4514168Sab196087 str = endptr; 4524168Sab196087 SKIP_BLANK; 4534168Sab196087 } 4544168Sab196087 } 4554168Sab196087 4564168Sab196087 /* Syntax error if anything is left over */ 4574168Sab196087 if (*str != '\0') 4584168Sab196087 return (0); 4594168Sab196087 4604168Sab196087 return (1); 4614168Sab196087 4624168Sab196087 #undef SKIP_BLANK 4634168Sab196087 } 4644168Sab196087 4654168Sab196087 /* 4665411Sab196087 * Process the symbolic name to value mappings passed to the 4675411Sab196087 * atoui() function. 4685411Sab196087 * 4695411Sab196087 * entry: 4705411Sab196087 * sym - NULL terminated array of name->value mappings. 4715411Sab196087 * value - Address of variable to receive corresponding value. 4725411Sab196087 * 4735411Sab196087 * exit: 4745411Sab196087 * If a mapping is found, *value is set to it, and True is returned. 4755411Sab196087 * Otherwise False is returned. 4765411Sab196087 */ 4775411Sab196087 static int 4785411Sab196087 atoui_sym_process(const char *str, const atoui_sym_t *sym, uint32_t *value) 4795411Sab196087 { 4805411Sab196087 size_t cmp_len; 4815411Sab196087 const char *tail; 4825411Sab196087 4835411Sab196087 while (isspace(*str)) 4845411Sab196087 str++; 4855411Sab196087 4865411Sab196087 tail = str + strlen(str); 4875411Sab196087 while ((tail > str) && isspace(*(tail - 1))) 4885411Sab196087 tail--; 4895411Sab196087 4905411Sab196087 cmp_len = tail - str; 4915411Sab196087 4925411Sab196087 for (; sym->sym_name != NULL; sym++) { 4935411Sab196087 if ((strlen(sym->sym_name) == cmp_len) && 4945411Sab196087 (strncasecmp(sym->sym_name, str, cmp_len) == 0)) { 4955411Sab196087 *value = sym->sym_value; 4965411Sab196087 return (1); 4975411Sab196087 } 4985411Sab196087 } 4995411Sab196087 5005411Sab196087 /* No symbolic mapping was found */ 5015411Sab196087 return (0); 5025411Sab196087 } 5035411Sab196087 5045411Sab196087 5055411Sab196087 /* 5065411Sab196087 * Convert a string to a numeric value. Strings starting with '0' 5075411Sab196087 * are taken to be octal, those staring with '0x' are hex, and all 5085411Sab196087 * others are decimal. 5095411Sab196087 * 5105411Sab196087 * entry: 5115411Sab196087 * str - String to be converted 5125411Sab196087 * sym - NULL, or NULL terminated array of name/value pairs. 5135411Sab196087 * v - Address of variable to receive resulting value. 5145411Sab196087 * 5155411Sab196087 * exit: 5165411Sab196087 * On success, returns True (1) and *v is set to the value. 5175411Sab196087 * On failure, returns False (0) and *v is undefined. 5185411Sab196087 */ 5195411Sab196087 static int 5205411Sab196087 atoui(const char *str, const atoui_sym_t *sym, uint32_t *v) 5215411Sab196087 { 5225411Sab196087 char *endptr; 5235411Sab196087 5245411Sab196087 if (sym && atoui_sym_process(str, sym, v)) 5255411Sab196087 return (1); 5265411Sab196087 5275411Sab196087 *v = strtoull(str, &endptr, 0); 5285411Sab196087 5295411Sab196087 /* If the left over part contains anything but whitespace, fail */ 5305411Sab196087 for (; *endptr; endptr++) 5315411Sab196087 if (!isspace(*endptr)) 5325411Sab196087 return (0); 5335411Sab196087 return (1); 5345411Sab196087 } 5355411Sab196087 5365411Sab196087 /* 5375411Sab196087 * Called after getopt() processing is finished if there is a non-empty 5385411Sab196087 * match list. Prepares the matching code for use. 5395411Sab196087 * 5405411Sab196087 * exit: 5415411Sab196087 * Returns True (1) if no errors are encountered. Writes an 5425411Sab196087 * error string to stderr and returns False (0) otherwise. 5435411Sab196087 */ 5445411Sab196087 static int 5455411Sab196087 match_prepare(char *argv0, uint_t flags) 5465411Sab196087 { 5475411Sab196087 atoui_sym_t *sym; 5485411Sab196087 match_rec_t *list; 5495411Sab196087 const char *str; 5505411Sab196087 int minus_p = (flags & FLG_SHOW_PHDR) != 0; 5515411Sab196087 5525411Sab196087 /* 5535411Sab196087 * Flag ambiguous attempt to use match option with both -p and 5545411Sab196087 * and one or more section SHOW options. In this case, we 5555411Sab196087 * can't tell what type of item we're supposed to match against. 5565411Sab196087 */ 5575411Sab196087 if (minus_p && (flags & FLG_MASK_SHOW_SHDR)) { 5585411Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_AMBIG_MATCH), 5595411Sab196087 basename(argv0)); 5605411Sab196087 return (0); 5615411Sab196087 } 5625411Sab196087 5635411Sab196087 /* Set the match type, based on the presence of the -p option */ 5645411Sab196087 if (minus_p) { 5655411Sab196087 match_state.item_type = MATCH_ITEM_PT; 5665411Sab196087 sym = sym_pt; 5675411Sab196087 } else { 5685411Sab196087 match_state.item_type = MATCH_ITEM_SHT; 5695411Sab196087 sym = sym_sht; 5705411Sab196087 } 5715411Sab196087 5725411Sab196087 /* 5735411Sab196087 * Scan match list and perform any necessary fixups: 5745411Sab196087 * 5755411Sab196087 * MATCH_OPT_NAME: If -p is specified, convert MATCH_OPT_NAME (-N) 5765411Sab196087 * requests into MATCH_OPT_TYPE (-T). 5775411Sab196087 * 5785411Sab196087 * MATCH_OPT_TYPE: Now that we know item type we are matching 5795411Sab196087 * against, we can convert the string saved in the name 5805411Sab196087 * field during getopt() processing into an integer and 5815411Sab196087 * write it into the type field. 5825411Sab196087 */ 5835411Sab196087 for (list = match_state.list; list; list = list->next) { 5845411Sab196087 if ((list->opt_type == MATCH_OPT_NAME) && minus_p) 5855411Sab196087 list->opt_type = MATCH_OPT_TYPE; 5865411Sab196087 5875411Sab196087 if (list->opt_type != MATCH_OPT_TYPE) 5885411Sab196087 continue; 5895411Sab196087 5905411Sab196087 str = list->value.name; 5915411Sab196087 if (atoui(str, sym, &list->value.type) == 0) { 5925411Sab196087 const char *fmt = minus_p ? 5935411Sab196087 MSG_INTL(MSG_ERR_BAD_T_PT) : 5945411Sab196087 MSG_INTL(MSG_ERR_BAD_T_SHT); 5955411Sab196087 5965411Sab196087 (void) fprintf(stderr, fmt, basename(argv0), str); 5975411Sab196087 return (0); 5985411Sab196087 } 5995411Sab196087 } 6005411Sab196087 6015411Sab196087 return (1); 6025411Sab196087 } 6035411Sab196087 6045411Sab196087 6055411Sab196087 /* 6064168Sab196087 * Returns True (1) if the item with the given name or index should 6074168Sab196087 * be displayed, and False (0) if it should not be. 6084168Sab196087 * 6094168Sab196087 * entry: 6105411Sab196087 * match_flags - Bitmask specifying matching options, as described 6115411Sab196087 * in _elfdump.h. 6125411Sab196087 * name - If MATCH_F_NAME flag is set, name of item under 6135411Sab196087 * consideration. Otherwise ignored. 6144168Sab196087 * should not be considered. 6155411Sab196087 * ndx - If MATCH_F_NDX flag is set, index of item under consideration. 6165411Sab196087 * type - If MATCH_F_TYPE is set, type of item under consideration. 6175411Sab196087 * If MATCH_F_PHDR is set, this would be a program 6185411Sab196087 * header type (PT_). Otherwise, a section header type (SHT_). 6194168Sab196087 * 6204168Sab196087 * exit: 6214168Sab196087 * True will be returned if the given name/index matches those given 6225411Sab196087 * by one of the (-I, -N -T) command line options, or if no such option 6235411Sab196087 * was used in the command invocation and MATCH_F_STRICT is not 6245411Sab196087 * set. 6254168Sab196087 */ 6264168Sab196087 int 6275411Sab196087 match(match_flags_t match_flags, const char *name, uint_t ndx, uint_t type) 6284168Sab196087 { 6295411Sab196087 match_item_t item_type = (match_flags & MATCH_F_PHDR) ? 6305411Sab196087 MATCH_ITEM_PT : MATCH_ITEM_SHT; 6315411Sab196087 match_rec_t *list; 6324168Sab196087 6335411Sab196087 /* 6345411Sab196087 * If there is no match list, then we use the MATCH_F_STRICT 6355411Sab196087 * flag to decide what to return. In the strict case, we return 6365411Sab196087 * False (0), in the normal case, True (1). 6375411Sab196087 */ 6385411Sab196087 if (match_state.list == NULL) 6395411Sab196087 return ((match_flags & MATCH_F_STRICT) == 0); 6405411Sab196087 6415411Sab196087 /* 6425411Sab196087 * If item being checked is not the current match type, 6435411Sab196087 * then allow it. 6445411Sab196087 */ 6455411Sab196087 if (item_type != match_state.item_type) 6464168Sab196087 return (1); 6474168Sab196087 6484168Sab196087 /* Run through the match records and check for a hit */ 6495411Sab196087 for (list = match_state.list; list; list = list->next) { 6505411Sab196087 switch (list->opt_type) { 6515411Sab196087 case MATCH_OPT_NAME: 6525411Sab196087 if (((match_flags & MATCH_F_NAME) == 0) || 6535411Sab196087 (name == NULL)) 6545411Sab196087 break; 6555411Sab196087 if (strcmp(list->value.name, name) == 0) 6564168Sab196087 return (1); 6574168Sab196087 break; 6585411Sab196087 case MATCH_OPT_NDX: 6595411Sab196087 if ((match_flags & MATCH_F_NDX) && 6605411Sab196087 (ndx == list->value.ndx.start)) 6614168Sab196087 return (1); 6624168Sab196087 break; 6635411Sab196087 case MATCH_OPT_RANGE: 6644168Sab196087 /* 6654168Sab196087 * A range end value less than 0 means that any value 6664168Sab196087 * above the start is acceptible. 6674168Sab196087 */ 6685411Sab196087 if ((match_flags & MATCH_F_NDX) && 6695411Sab196087 (ndx >= list->value.ndx.start) && 6704168Sab196087 ((list->value.ndx.end < 0) || 6714168Sab196087 (ndx <= list->value.ndx.end))) 6724168Sab196087 return (1); 6734168Sab196087 break; 6745411Sab196087 6755411Sab196087 case MATCH_OPT_TYPE: 6765411Sab196087 if ((match_flags & MATCH_F_TYPE) && 6775411Sab196087 (type == list->value.type)) 6785411Sab196087 return (1); 6795411Sab196087 break; 6804168Sab196087 } 6814168Sab196087 } 6824168Sab196087 6834168Sab196087 /* Nothing matched */ 6844168Sab196087 return (0); 6854168Sab196087 } 6864168Sab196087 6874168Sab196087 /* 6885411Sab196087 * Add an entry to match_state.list for use by match(). This routine is for 6895411Sab196087 * use during getopt() processing. It should not be called once 6905411Sab196087 * match_prepare() has been called. 6914168Sab196087 * 6924168Sab196087 * Return True (1) for success. On failure, an error is written 6934168Sab196087 * to stderr, and False (0) is returned. 6944168Sab196087 */ 6954168Sab196087 static int 6965411Sab196087 add_match_record(char *argv0, match_rec_t *data) 6974168Sab196087 { 6985411Sab196087 match_rec_t *rec; 6995411Sab196087 match_rec_t *list; 7004168Sab196087 7014168Sab196087 if ((rec = malloc(sizeof (*rec))) == NULL) { 7024168Sab196087 int err = errno; 7034168Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC), 7044168Sab196087 basename(argv0), strerror(err)); 7054168Sab196087 return (0); 7064168Sab196087 } 7074168Sab196087 7084168Sab196087 *rec = *data; 7094168Sab196087 7105411Sab196087 /* Insert at end of match_state.list */ 7115411Sab196087 if (match_state.list == NULL) { 7125411Sab196087 match_state.list = rec; 7134168Sab196087 } else { 7145411Sab196087 for (list = match_state.list; list->next != NULL; 7155411Sab196087 list = list->next) 7164168Sab196087 ; 7174168Sab196087 list->next = rec; 7184168Sab196087 } 7194168Sab196087 7204168Sab196087 rec->next = NULL; 7214168Sab196087 return (1); 7221618Srie } 7231618Srie 7245411Sab196087 static int 7255411Sab196087 decide(const char *file, int fd, Elf *elf, uint_t flags, 7265411Sab196087 const char *wname, int wfd) 7271618Srie { 7285411Sab196087 int r; 7295411Sab196087 7301618Srie if (gelf_getclass(elf) == ELFCLASS64) 7315411Sab196087 r = regular64(file, fd, elf, flags, wname, wfd); 7321618Srie else 7335411Sab196087 r = regular32(file, fd, elf, flags, wname, wfd); 7345411Sab196087 7355411Sab196087 return (r); 7361618Srie } 7371618Srie 7385411Sab196087 static int 7395411Sab196087 archive(const char *file, int fd, Elf *elf, uint_t flags, 7405411Sab196087 const char *wname, int wfd) 7411618Srie { 7421618Srie Elf_Cmd cmd = ELF_C_READ; 7431618Srie Elf_Arhdr *arhdr; 7441618Srie Elf *_elf = 0; 7451618Srie size_t ptr; 7461618Srie Elf_Arsym *arsym = 0; 7471618Srie 7481618Srie /* 7493492Sab196087 * Determine if the archive symbol table itself is required. 7501618Srie */ 7515411Sab196087 if ((flags & FLG_SHOW_SYMBOLS) && 7525411Sab196087 match(MATCH_F_NAME, MSG_ORIG(MSG_ELF_ARSYM), 0, 0)) { 7531618Srie /* 7541618Srie * Get the archive symbol table. 7551618Srie */ 7561618Srie if (((arsym = elf_getarsym(elf, &ptr)) == 0) && elf_errno()) { 7571618Srie /* 7581618Srie * The arsym could be 0 even though there was no error. 7591618Srie * Print the error message only when there was 7601618Srie * real error from elf_getarsym(). 7611618Srie */ 7621618Srie failure(file, MSG_ORIG(MSG_ELF_GETARSYM)); 7635411Sab196087 return (0); 7641618Srie } 7651618Srie } 7661618Srie 7671618Srie /* 7681618Srie * Print the archive symbol table only when the archive symbol 7691618Srie * table exists and it was requested to print. 7701618Srie */ 7711618Srie if (arsym) { 7721618Srie size_t cnt; 7731618Srie char index[MAXNDXSIZE]; 7741618Srie size_t offset = 0, _offset = 0; 7751618Srie 7761618Srie /* 7771618Srie * Print out all the symbol entries. 7781618Srie */ 7791618Srie dbg_print(0, MSG_INTL(MSG_ARCHIVE_SYMTAB)); 7801618Srie dbg_print(0, MSG_INTL(MSG_ARCHIVE_FIELDS)); 7811618Srie 7821618Srie for (cnt = 0; cnt < ptr; cnt++, arsym++) { 7831618Srie /* 7841618Srie * For each object obtain an elf descriptor so that we 7851618Srie * can establish the members name. Note, we have had 7861618Srie * archives where the archive header has not been 7871618Srie * obtainable so be lenient with errors. 7881618Srie */ 7891618Srie if ((offset == 0) || ((arsym->as_off != 0) && 7901618Srie (arsym->as_off != _offset))) { 7911618Srie 7921618Srie if (_elf) 7931618Srie (void) elf_end(_elf); 7941618Srie 7951618Srie if (elf_rand(elf, arsym->as_off) != 7961618Srie arsym->as_off) { 7971618Srie failure(file, MSG_ORIG(MSG_ELF_RAND)); 7981618Srie arhdr = 0; 7991618Srie } else if ((_elf = elf_begin(fd, 8001618Srie ELF_C_READ, elf)) == 0) { 8011618Srie failure(file, MSG_ORIG(MSG_ELF_BEGIN)); 8021618Srie arhdr = 0; 8031618Srie } else if ((arhdr = elf_getarhdr(_elf)) == 0) { 8041618Srie failure(file, 8051618Srie MSG_ORIG(MSG_ELF_GETARHDR)); 8061618Srie arhdr = 0; 8071618Srie } 8081618Srie 8091618Srie _offset = arsym->as_off; 8101618Srie if (offset == 0) 8111618Srie offset = _offset; 8121618Srie } 8131618Srie 8141618Srie (void) snprintf(index, MAXNDXSIZE, 8151618Srie MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(cnt)); 8161618Srie if (arsym->as_off) 8171618Srie dbg_print(0, MSG_ORIG(MSG_FMT_ARSYM1), index, 8181618Srie /* LINTED */ 8191618Srie (int)arsym->as_off, arhdr ? arhdr->ar_name : 8201618Srie MSG_INTL(MSG_STR_UNKNOWN), (arsym->as_name ? 8211618Srie demangle(arsym->as_name, flags) : 8221618Srie MSG_INTL(MSG_STR_NULL))); 8231618Srie else 8241618Srie dbg_print(0, MSG_ORIG(MSG_FMT_ARSYM2), index, 8251618Srie /* LINTED */ 8261618Srie (int)arsym->as_off); 8271618Srie } 8281618Srie 8291618Srie if (_elf) 8301618Srie (void) elf_end(_elf); 8311618Srie 8321618Srie /* 8331618Srie * If we only need the archive symbol table return. 8341618Srie */ 8355411Sab196087 if ((flags & FLG_SHOW_SYMBOLS) && 8365411Sab196087 match(MATCH_F_STRICT | MATCH_F_NAME, 8375411Sab196087 MSG_ORIG(MSG_ELF_ARSYM), -1, -1)) 8385411Sab196087 return (0); 8391618Srie 8401618Srie /* 8411618Srie * Reset elf descriptor in preparation for processing each 8421618Srie * member. 8431618Srie */ 8441618Srie if (offset) 8451618Srie (void) elf_rand(elf, offset); 8461618Srie } 8471618Srie 8481618Srie /* 8491618Srie * Process each object within the archive. 8501618Srie */ 8511618Srie while ((_elf = elf_begin(fd, cmd, elf)) != NULL) { 8521618Srie char name[MAXPATHLEN]; 8531618Srie 8541618Srie if ((arhdr = elf_getarhdr(_elf)) == NULL) { 8551618Srie failure(file, MSG_ORIG(MSG_ELF_GETARHDR)); 8565411Sab196087 return (0); 8571618Srie } 8581618Srie if (*arhdr->ar_name != '/') { 8591618Srie (void) snprintf(name, MAXPATHLEN, 8601618Srie MSG_ORIG(MSG_FMT_ARNAME), file, arhdr->ar_name); 8611618Srie dbg_print(0, MSG_ORIG(MSG_FMT_NLSTR), name); 8621618Srie 8631618Srie switch (elf_kind(_elf)) { 8641618Srie case ELF_K_AR: 8655411Sab196087 if (archive(name, fd, _elf, flags, 8665411Sab196087 wname, wfd) == 1) 8675411Sab196087 return (1); 8681618Srie break; 8691618Srie case ELF_K_ELF: 8705411Sab196087 if (decide(name, fd, _elf, flags, 8715411Sab196087 wname, wfd) == 1) 8725411Sab196087 return (1); 8731618Srie break; 8741618Srie default: 8751618Srie (void) fprintf(stderr, 8761618Srie MSG_INTL(MSG_ERR_BADFILE), name); 8771618Srie break; 8781618Srie } 8791618Srie } 8801618Srie 8811618Srie cmd = elf_next(_elf); 8821618Srie (void) elf_end(_elf); 8831618Srie } 8845411Sab196087 8855411Sab196087 return (0); 8861618Srie } 8871618Srie 8881618Srie int 8891618Srie main(int argc, char **argv, char **envp) 8901618Srie { 8911618Srie Elf *elf; 8921618Srie int var, fd, wfd = 0; 8935411Sab196087 char *wname = NULL; 8941618Srie uint_t flags = 0; 8955411Sab196087 match_rec_t match_data; 8965411Sab196087 int ret; 8971618Srie 8981618Srie /* 8991618Srie * If we're on a 64-bit kernel, try to exec a full 64-bit version of 9001618Srie * the binary. If successful, conv_check_native() won't return. 9011618Srie */ 9022647Srie (void) conv_check_native(argv, envp); 9031618Srie 9041618Srie /* 9051618Srie * Establish locale. 9061618Srie */ 9071618Srie (void) setlocale(LC_MESSAGES, MSG_ORIG(MSG_STR_EMPTY)); 9081618Srie (void) textdomain(MSG_ORIG(MSG_SUNW_OST_SGS)); 9091618Srie 9101618Srie (void) setvbuf(stdout, NULL, _IOLBF, 0); 9111618Srie (void) setvbuf(stderr, NULL, _IOLBF, 0); 9121618Srie 9131618Srie opterr = 0; 9141618Srie while ((var = getopt(argc, argv, MSG_ORIG(MSG_STR_OPTIONS))) != EOF) { 9151618Srie switch (var) { 9161618Srie case 'C': 9175411Sab196087 flags |= FLG_CTL_DEMANGLE; 9181618Srie break; 9191618Srie case 'c': 9205411Sab196087 flags |= FLG_SHOW_SHDR; 9211618Srie break; 9221618Srie case 'd': 9235411Sab196087 flags |= FLG_SHOW_DYNAMIC; 9241618Srie break; 9251618Srie case 'e': 9265411Sab196087 flags |= FLG_SHOW_EHDR; 9271618Srie break; 9281618Srie case 'G': 9295411Sab196087 flags |= FLG_SHOW_GOT; 9301618Srie break; 9311618Srie case 'g': 9325411Sab196087 flags |= FLG_SHOW_GROUP; 9331618Srie break; 9341618Srie case 'H': 9355411Sab196087 flags |= FLG_SHOW_CAP; 9361618Srie break; 9371618Srie case 'h': 9385411Sab196087 flags |= FLG_SHOW_HASH; 9391618Srie break; 9404168Sab196087 case 'I': 9415411Sab196087 if (!process_index_opt(optarg, &match_data)) 9425411Sab196087 goto usage_brief; 9434168Sab196087 if (!add_match_record(argv[0], &match_data)) 9444168Sab196087 return (1); 9455411Sab196087 flags |= FLG_CTL_MATCH; 9464168Sab196087 break; 9471618Srie case 'i': 9485411Sab196087 flags |= FLG_SHOW_INTERP; 9491618Srie break; 9501618Srie case 'k': 9515411Sab196087 flags |= FLG_CALC_CHECKSUM; 9521618Srie break; 9531618Srie case 'l': 9545411Sab196087 flags |= FLG_CTL_LONGNAME; 9551618Srie break; 9561618Srie case 'm': 9575411Sab196087 flags |= FLG_SHOW_MOVE; 9581618Srie break; 9591618Srie case 'N': 9605411Sab196087 match_data.opt_type = MATCH_OPT_NAME; 9614168Sab196087 match_data.value.name = optarg; 9624168Sab196087 if (!add_match_record(argv[0], &match_data)) 9634168Sab196087 return (1); 9645411Sab196087 flags |= FLG_CTL_MATCH; 9651618Srie break; 9661618Srie case 'n': 9675411Sab196087 flags |= FLG_SHOW_NOTE; 9681618Srie break; 9694665Sab196087 case 'P': 9705411Sab196087 flags |= FLG_CTL_FAKESHDR; 9714665Sab196087 break; 9721618Srie case 'p': 9735411Sab196087 flags |= FLG_SHOW_PHDR; 9741618Srie break; 9751618Srie case 'r': 9765411Sab196087 flags |= FLG_SHOW_RELOC; 9771618Srie break; 9783492Sab196087 case 'S': 9795411Sab196087 flags |= FLG_SHOW_SORT; 9803492Sab196087 break; 9811618Srie case 's': 9825411Sab196087 flags |= FLG_SHOW_SYMBOLS; 9835411Sab196087 break; 9845411Sab196087 case 'T': 9855411Sab196087 /* 9865411Sab196087 * We can't evaluate the value yet, because 9875411Sab196087 * we need to know if -p is used or not in 9885411Sab196087 * order to tell if we're seeing section header 9895411Sab196087 * or program header types. So, we save the 9905411Sab196087 * string in the name field, and then convert 9915411Sab196087 * it to a type integer in a following pass. 9925411Sab196087 */ 9935411Sab196087 match_data.opt_type = MATCH_OPT_TYPE; 9945411Sab196087 match_data.value.name = optarg; 9955411Sab196087 if (!add_match_record(argv[0], &match_data)) 9965411Sab196087 return (1); 9975411Sab196087 flags |= FLG_CTL_MATCH; 9981618Srie break; 9991618Srie case 'u': 10005411Sab196087 flags |= FLG_SHOW_UNWIND; 10011618Srie break; 10021618Srie case 'v': 10035411Sab196087 flags |= FLG_SHOW_VERSIONS; 10041618Srie break; 10051618Srie case 'w': 10061618Srie wname = optarg; 10071618Srie break; 10081618Srie case 'y': 10095411Sab196087 flags |= FLG_SHOW_SYMINFO; 10101618Srie break; 10111618Srie case '?': 10121618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF), 10131618Srie basename(argv[0])); 10141618Srie detail_usage(); 10151618Srie return (1); 10161618Srie default: 10171618Srie break; 10181618Srie } 10191618Srie } 10201618Srie 10215411Sab196087 /* -p and -w are mutually exclusive. -w only works with sections */ 10225411Sab196087 if (((flags & FLG_SHOW_PHDR) != 0) && (wname != NULL)) 10235411Sab196087 goto usage_brief; 10245411Sab196087 10255411Sab196087 /* If a match argument is present, prepare the match state */ 10265411Sab196087 if ((match_state.list != NULL) && (match_prepare(argv[0], flags) == 0)) 10275411Sab196087 return (1); 10285411Sab196087 10291618Srie /* 10305411Sab196087 * Decide what to do if no options specifying something to 10315411Sab196087 * show or do are present. 10325411Sab196087 * 10335411Sab196087 * If there is no -w and no match options, then we will set all 10345411Sab196087 * the show flags, causing a full display of everything in the 10355411Sab196087 * file that we know how to handle. 10365411Sab196087 * 10375411Sab196087 * Otherwise, if there is no match list, we generate a usage 10385411Sab196087 * error and quit. 10395411Sab196087 * 10405411Sab196087 * In the case where there is a match list, we go ahead and call 10415411Sab196087 * regular() anyway, leaving it to decide what to do. If -w is 10425411Sab196087 * present, regular() will use the match list to handle it. 10435411Sab196087 * In addition, in the absence of explicit show/calc flags, regular() 10445411Sab196087 * will compare the section headers to the match list and use 10455411Sab196087 * that to generate the FLG_ bits that will display the information 10465411Sab196087 * specified by the match list. 10471618Srie */ 10485411Sab196087 if ((flags & ~FLG_MASK_CTL) == 0) { 10495411Sab196087 if (!wname && (match_state.list == NULL)) 10505411Sab196087 flags |= FLG_MASK_SHOW; 10515411Sab196087 else if (match_state.list == NULL) 10525411Sab196087 goto usage_brief; 10531618Srie } 10541618Srie 10555411Sab196087 /* There needs to be at least 1 filename left following the options */ 10565411Sab196087 if ((var = argc - optind) == 0) 10575411Sab196087 goto usage_brief; 10581618Srie 10591618Srie /* 10601618Srie * If the -l/-C option is specified, set up the liblddbg.so. 10611618Srie */ 10625411Sab196087 if (flags & FLG_CTL_LONGNAME) 10631618Srie dbg_desc->d_extra |= DBG_E_LONG; 10645411Sab196087 if (flags & FLG_CTL_DEMANGLE) 10651618Srie dbg_desc->d_extra |= DBG_E_DEMANGLE; 10661618Srie 10671618Srie /* 10681618Srie * If the -w option has indicated an output file open it. It's 10691618Srie * arguable whether this option has much use when multiple files are 10701618Srie * being processed. 10715411Sab196087 * 10725411Sab196087 * If wname is non-NULL, we know that -p was not specified, due 10735411Sab196087 * to the test above. 10741618Srie */ 10751618Srie if (wname) { 10761618Srie if ((wfd = open(wname, (O_RDWR | O_CREAT | O_TRUNC), 10771618Srie 0666)) < 0) { 10781618Srie int err = errno; 10791618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_OPEN), 10801618Srie wname, strerror(err)); 10815411Sab196087 return (1); 10821618Srie } 10831618Srie } 10841618Srie 10851618Srie /* 10865411Sab196087 * Open the input file, initialize the elf interface, and 10875411Sab196087 * process it. 10881618Srie */ 10895411Sab196087 ret = 0; 10905411Sab196087 for (; (optind < argc) && (ret == 0); optind++) { 10911618Srie const char *file = argv[optind]; 10921618Srie 10931618Srie if ((fd = open(argv[optind], O_RDONLY)) == -1) { 10941618Srie int err = errno; 10951618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_OPEN), 10961618Srie file, strerror(err)); 10971618Srie continue; 10981618Srie } 10991618Srie (void) elf_version(EV_CURRENT); 11001618Srie if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { 11011618Srie failure(file, MSG_ORIG(MSG_ELF_BEGIN)); 11021618Srie (void) close(fd); 11031618Srie continue; 11041618Srie } 11051618Srie 11061618Srie if (var > 1) 11071618Srie dbg_print(0, MSG_ORIG(MSG_FMT_NLSTRNL), file); 11081618Srie 11091618Srie switch (elf_kind(elf)) { 11101618Srie case ELF_K_AR: 11115411Sab196087 ret = archive(file, fd, elf, flags, wname, wfd); 11121618Srie break; 11131618Srie case ELF_K_ELF: 11145411Sab196087 ret = decide(file, fd, elf, flags, wname, wfd); 11151618Srie break; 11161618Srie default: 11171618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADFILE), file); 11181618Srie break; 11191618Srie } 11201618Srie 11211618Srie (void) close(fd); 11221618Srie (void) elf_end(elf); 11231618Srie } 11241618Srie 11251618Srie if (wfd) 11261618Srie (void) close(wfd); 11275411Sab196087 return (ret); 11285411Sab196087 11295411Sab196087 usage_brief: 11305411Sab196087 /* Control comes here for a simple usage message and exit */ 11315411Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF), 11325411Sab196087 basename(argv[0])); 11335411Sab196087 return (1); 11345411Sab196087 11351618Srie } 1136