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*9085SAli.Bahrami@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 241618Srie * Use is subject to license terms. 251618Srie */ 261618Srie 271618Srie /* 281618Srie * Dump an elf file. 291618Srie */ 301618Srie #include <sys/param.h> 311618Srie #include <fcntl.h> 321618Srie #include <stdio.h> 334168Sab196087 #include <stdlib.h> 344168Sab196087 #include <ctype.h> 351618Srie #include <libelf.h> 361618Srie #include <link.h> 371618Srie #include <stdarg.h> 381618Srie #include <unistd.h> 391618Srie #include <libgen.h> 401618Srie #include <libintl.h> 411618Srie #include <locale.h> 421618Srie #include <errno.h> 431618Srie #include <strings.h> 441618Srie #include <debug.h> 451618Srie #include <conv.h> 461618Srie #include <msg.h> 471618Srie #include <_elfdump.h> 485411Sab196087 #include <sys/elf_SPARC.h> 495411Sab196087 #include <sys/elf_amd64.h> 505411Sab196087 511618Srie 524063Sab196087 const Cache cache_init = {NULL, NULL, NULL, NULL, 0}; 531618Srie 544168Sab196087 554168Sab196087 565411Sab196087 /* 575411Sab196087 * The -I, -N, and -T options are called "match options", because 585411Sab196087 * they allow selecting the items to be displayed based on matching 595411Sab196087 * their index, name, or type. 605411Sab196087 * 615411Sab196087 * The ELF information to which -I, -N, or -T are applied in 625411Sab196087 * the current invocation is called the "match item". 635411Sab196087 */ 644168Sab196087 typedef enum { 655411Sab196087 MATCH_ITEM_PT, /* Program header (PT_) */ 665411Sab196087 MATCH_ITEM_SHT /* Section header (SHT_) */ 675411Sab196087 } match_item_t; 685411Sab196087 695411Sab196087 /* match_opt_t is used to note which match option was used */ 705411Sab196087 typedef enum { 715411Sab196087 MATCH_OPT_NAME, /* Record contains a name */ 725411Sab196087 MATCH_OPT_NDX, /* Record contains a single index */ 735411Sab196087 MATCH_OPT_RANGE, /* Record contains an index range */ 745411Sab196087 MATCH_OPT_TYPE, /* Record contains a type (shdr or phdr) */ 755411Sab196087 } match_opt_t; 764168Sab196087 774168Sab196087 typedef struct _match { 784168Sab196087 struct _match *next; /* Pointer to next item in list */ 795411Sab196087 match_opt_t opt_type; 804168Sab196087 union { 815411Sab196087 const char *name; /* MATCH_OPT_NAME */ 825411Sab196087 struct { /* MATCH_OPT_NDX and MATCH_OPT_RANGE */ 834168Sab196087 int start; 845411Sab196087 int end; /* Only for MATCH_OPT_RANGE */ 854168Sab196087 } ndx; 865411Sab196087 uint32_t type; /* MATCH_OPT_TYPE */ 874168Sab196087 } value; 885411Sab196087 } match_rec_t; 895411Sab196087 905411Sab196087 static struct { 915411Sab196087 match_item_t item_type; /* Type of item being matched */ 925411Sab196087 match_rec_t *list; /* Records for (-I, -N, -T) options */ 935411Sab196087 } match_state; 945411Sab196087 955411Sab196087 965411Sab196087 975411Sab196087 /* Map names to their integer value */ 985411Sab196087 typedef struct { 995411Sab196087 const char *sym_name; 1005411Sab196087 uint32_t sym_value; 1015411Sab196087 } atoui_sym_t; 1025411Sab196087 1035411Sab196087 /* 1045411Sab196087 * ELF section types. 1055411Sab196087 */ 1065411Sab196087 static atoui_sym_t sym_sht[] = { 1075411Sab196087 { MSG_ORIG(MSG_SHT_NULL), SHT_NULL }, 1085411Sab196087 { MSG_ORIG(MSG_SHT_NULL_ALT1), SHT_NULL }, 1095411Sab196087 1105411Sab196087 { MSG_ORIG(MSG_SHT_PROGBITS), SHT_PROGBITS }, 1115411Sab196087 { MSG_ORIG(MSG_SHT_PROGBITS_ALT1), SHT_PROGBITS }, 1125411Sab196087 1135411Sab196087 { MSG_ORIG(MSG_SHT_SYMTAB), SHT_SYMTAB }, 1145411Sab196087 { MSG_ORIG(MSG_SHT_SYMTAB_ALT1), SHT_SYMTAB }, 1155411Sab196087 1165411Sab196087 { MSG_ORIG(MSG_SHT_STRTAB), SHT_STRTAB }, 1175411Sab196087 { MSG_ORIG(MSG_SHT_STRTAB_ALT1), SHT_STRTAB }, 1185411Sab196087 1195411Sab196087 { MSG_ORIG(MSG_SHT_RELA), SHT_RELA }, 1205411Sab196087 { MSG_ORIG(MSG_SHT_RELA_ALT1), SHT_RELA }, 1215411Sab196087 1225411Sab196087 { MSG_ORIG(MSG_SHT_HASH), SHT_HASH }, 1235411Sab196087 { MSG_ORIG(MSG_SHT_HASH_ALT1), SHT_HASH }, 1245411Sab196087 1255411Sab196087 { MSG_ORIG(MSG_SHT_DYNAMIC), SHT_DYNAMIC }, 1265411Sab196087 { MSG_ORIG(MSG_SHT_DYNAMIC_ALT1), SHT_DYNAMIC }, 1275411Sab196087 1285411Sab196087 { MSG_ORIG(MSG_SHT_NOTE), SHT_NOTE }, 1295411Sab196087 { MSG_ORIG(MSG_SHT_NOTE_ALT1), SHT_NOTE }, 1305411Sab196087 1315411Sab196087 { MSG_ORIG(MSG_SHT_NOBITS), SHT_NOBITS }, 1325411Sab196087 { MSG_ORIG(MSG_SHT_NOBITS_ALT1), SHT_NOBITS }, 1335411Sab196087 1345411Sab196087 { MSG_ORIG(MSG_SHT_REL), SHT_REL }, 1355411Sab196087 { MSG_ORIG(MSG_SHT_REL_ALT1), SHT_REL }, 1365411Sab196087 1375411Sab196087 { MSG_ORIG(MSG_SHT_SHLIB), SHT_SHLIB }, 1385411Sab196087 { MSG_ORIG(MSG_SHT_SHLIB_ALT1), SHT_SHLIB }, 1395411Sab196087 1405411Sab196087 { MSG_ORIG(MSG_SHT_DYNSYM), SHT_DYNSYM }, 1415411Sab196087 { MSG_ORIG(MSG_SHT_DYNSYM_ALT1), SHT_DYNSYM }, 1425411Sab196087 1435411Sab196087 { MSG_ORIG(MSG_SHT_INIT_ARRAY), SHT_INIT_ARRAY }, 1445411Sab196087 { MSG_ORIG(MSG_SHT_INIT_ARRAY_ALT1), SHT_INIT_ARRAY }, 1455411Sab196087 1465411Sab196087 { MSG_ORIG(MSG_SHT_FINI_ARRAY), SHT_FINI_ARRAY }, 1475411Sab196087 { MSG_ORIG(MSG_SHT_FINI_ARRAY_ALT1), SHT_FINI_ARRAY }, 1485411Sab196087 1495411Sab196087 { MSG_ORIG(MSG_SHT_PREINIT_ARRAY), SHT_PREINIT_ARRAY }, 1505411Sab196087 { MSG_ORIG(MSG_SHT_PREINIT_ARRAY_ALT1), SHT_PREINIT_ARRAY }, 1515411Sab196087 1525411Sab196087 { MSG_ORIG(MSG_SHT_GROUP), SHT_GROUP }, 1535411Sab196087 { MSG_ORIG(MSG_SHT_GROUP_ALT1), SHT_GROUP }, 1545411Sab196087 1555411Sab196087 { MSG_ORIG(MSG_SHT_SYMTAB_SHNDX), SHT_SYMTAB_SHNDX }, 1565411Sab196087 { MSG_ORIG(MSG_SHT_SYMTAB_SHNDX_ALT1), SHT_SYMTAB_SHNDX }, 1575411Sab196087 1585411Sab196087 { MSG_ORIG(MSG_SHT_SUNW_SYMSORT), SHT_SUNW_symsort }, 1595411Sab196087 { MSG_ORIG(MSG_SHT_SUNW_SYMSORT_ALT1), SHT_SUNW_symsort }, 1605411Sab196087 1615411Sab196087 { MSG_ORIG(MSG_SHT_SUNW_TLSSORT), SHT_SUNW_tlssort }, 1625411Sab196087 { MSG_ORIG(MSG_SHT_SUNW_TLSSORT_ALT1), SHT_SUNW_tlssort }, 1635411Sab196087 1645411Sab196087 { MSG_ORIG(MSG_SHT_SUNW_LDYNSYM), SHT_SUNW_LDYNSYM }, 1655411Sab196087 { MSG_ORIG(MSG_SHT_SUNW_LDYNSYM_ALT1), SHT_SUNW_LDYNSYM }, 1665411Sab196087 1675411Sab196087 { MSG_ORIG(MSG_SHT_SUNW_DOF), SHT_SUNW_dof }, 1685411Sab196087 { MSG_ORIG(MSG_SHT_SUNW_DOF_ALT1), SHT_SUNW_dof }, 1695411Sab196087 1705411Sab196087 { MSG_ORIG(MSG_SHT_SUNW_CAP), SHT_SUNW_cap }, 1715411Sab196087 { MSG_ORIG(MSG_SHT_SUNW_CAP_ALT1), SHT_SUNW_cap }, 1725411Sab196087 1735411Sab196087 { MSG_ORIG(MSG_SHT_SUNW_SIGNATURE), SHT_SUNW_SIGNATURE }, 1745411Sab196087 { MSG_ORIG(MSG_SHT_SUNW_SIGNATURE_ALT1), SHT_SUNW_SIGNATURE }, 1755411Sab196087 1765411Sab196087 { MSG_ORIG(MSG_SHT_SUNW_ANNOTATE), SHT_SUNW_ANNOTATE }, 1775411Sab196087 { MSG_ORIG(MSG_SHT_SUNW_ANNOTATE_ALT1), SHT_SUNW_ANNOTATE }, 1784168Sab196087 1795411Sab196087 { MSG_ORIG(MSG_SHT_SUNW_DEBUGSTR), SHT_SUNW_DEBUGSTR }, 1805411Sab196087 { MSG_ORIG(MSG_SHT_SUNW_DEBUGSTR_ALT1), SHT_SUNW_DEBUGSTR }, 1815411Sab196087 1825411Sab196087 { MSG_ORIG(MSG_SHT_SUNW_DEBUG), SHT_SUNW_DEBUG }, 1835411Sab196087 { MSG_ORIG(MSG_SHT_SUNW_DEBUG_ALT1), SHT_SUNW_DEBUG }, 1845411Sab196087 1855411Sab196087 { MSG_ORIG(MSG_SHT_SUNW_MOVE), SHT_SUNW_move }, 1865411Sab196087 { MSG_ORIG(MSG_SHT_SUNW_MOVE_ALT1), SHT_SUNW_move }, 1875411Sab196087 1885411Sab196087 { MSG_ORIG(MSG_SHT_SUNW_COMDAT), SHT_SUNW_COMDAT }, 1895411Sab196087 { MSG_ORIG(MSG_SHT_SUNW_COMDAT_ALT1), SHT_SUNW_COMDAT }, 1905411Sab196087 1915411Sab196087 { MSG_ORIG(MSG_SHT_SUNW_SYMINFO), SHT_SUNW_syminfo }, 1925411Sab196087 { MSG_ORIG(MSG_SHT_SUNW_SYMINFO_ALT1), SHT_SUNW_syminfo }, 1935411Sab196087 1945411Sab196087 { MSG_ORIG(MSG_SHT_SUNW_VERDEF), SHT_SUNW_verdef }, 1955411Sab196087 { MSG_ORIG(MSG_SHT_SUNW_VERDEF_ALT1), SHT_SUNW_verdef }, 1965411Sab196087 1975411Sab196087 { MSG_ORIG(MSG_SHT_GNU_VERDEF), SHT_GNU_verdef }, 1985411Sab196087 { MSG_ORIG(MSG_SHT_GNU_VERDEF_ALT1), SHT_GNU_verdef }, 1995411Sab196087 2005411Sab196087 { MSG_ORIG(MSG_SHT_SUNW_VERNEED), SHT_SUNW_verneed }, 2015411Sab196087 { MSG_ORIG(MSG_SHT_SUNW_VERNEED_ALT1), SHT_SUNW_verneed }, 2025411Sab196087 2035411Sab196087 { MSG_ORIG(MSG_SHT_GNU_VERNEED), SHT_GNU_verneed }, 2045411Sab196087 { MSG_ORIG(MSG_SHT_GNU_VERNEED_ALT1), SHT_GNU_verneed }, 2055411Sab196087 2065411Sab196087 { MSG_ORIG(MSG_SHT_SUNW_VERSYM), SHT_SUNW_versym }, 2075411Sab196087 { MSG_ORIG(MSG_SHT_SUNW_VERSYM_ALT1), SHT_SUNW_versym }, 2085411Sab196087 2095411Sab196087 { MSG_ORIG(MSG_SHT_GNU_VERSYM), SHT_GNU_versym }, 2105411Sab196087 { MSG_ORIG(MSG_SHT_GNU_VERSYM_ALT1), SHT_GNU_versym }, 2115411Sab196087 2125411Sab196087 { MSG_ORIG(MSG_SHT_SPARC_GOTDATA), SHT_SPARC_GOTDATA }, 2135411Sab196087 { MSG_ORIG(MSG_SHT_SPARC_GOTDATA_ALT1), SHT_SPARC_GOTDATA }, 2145411Sab196087 2155411Sab196087 { MSG_ORIG(MSG_SHT_AMD64_UNWIND), SHT_AMD64_UNWIND }, 2165411Sab196087 { MSG_ORIG(MSG_SHT_AMD64_UNWIND_ALT1), SHT_AMD64_UNWIND }, 2175411Sab196087 2185411Sab196087 { NULL } 2195411Sab196087 }; 2205411Sab196087 2215411Sab196087 /* 2225411Sab196087 * Program header PT_* type values 2235411Sab196087 */ 2245411Sab196087 static atoui_sym_t sym_pt[] = { 2255411Sab196087 { MSG_ORIG(MSG_PT_NULL), PT_NULL }, 2265411Sab196087 { MSG_ORIG(MSG_PT_NULL_ALT1), PT_NULL }, 2275411Sab196087 2285411Sab196087 { MSG_ORIG(MSG_PT_LOAD), PT_LOAD }, 2295411Sab196087 { MSG_ORIG(MSG_PT_LOAD_ALT1), PT_LOAD }, 2305411Sab196087 2315411Sab196087 { MSG_ORIG(MSG_PT_DYNAMIC), PT_DYNAMIC }, 2325411Sab196087 { MSG_ORIG(MSG_PT_DYNAMIC_ALT1), PT_DYNAMIC }, 2335411Sab196087 2345411Sab196087 { MSG_ORIG(MSG_PT_INTERP), PT_INTERP }, 2355411Sab196087 { MSG_ORIG(MSG_PT_INTERP_ALT1), PT_INTERP }, 2365411Sab196087 2375411Sab196087 { MSG_ORIG(MSG_PT_NOTE), PT_NOTE }, 2385411Sab196087 { MSG_ORIG(MSG_PT_NOTE_ALT1), PT_NOTE }, 2395411Sab196087 2405411Sab196087 { MSG_ORIG(MSG_PT_SHLIB), PT_SHLIB }, 2415411Sab196087 { MSG_ORIG(MSG_PT_SHLIB_ALT1), PT_SHLIB }, 2425411Sab196087 2435411Sab196087 { MSG_ORIG(MSG_PT_PHDR), PT_PHDR }, 2445411Sab196087 { MSG_ORIG(MSG_PT_PHDR_ALT1), PT_PHDR }, 2455411Sab196087 2465411Sab196087 { MSG_ORIG(MSG_PT_TLS), PT_TLS }, 2475411Sab196087 { MSG_ORIG(MSG_PT_TLS_ALT1), PT_TLS }, 2485411Sab196087 2495411Sab196087 { MSG_ORIG(MSG_PT_SUNW_UNWIND), PT_SUNW_UNWIND }, 2505411Sab196087 { MSG_ORIG(MSG_PT_SUNW_UNWIND_ALT1), PT_SUNW_UNWIND }, 2515411Sab196087 252*9085SAli.Bahrami@Sun.COM { MSG_ORIG(MSG_PT_SUNW_EH_FRAME), PT_SUNW_EH_FRAME }, 253*9085SAli.Bahrami@Sun.COM { MSG_ORIG(MSG_PT_SUNW_EH_FRAME_ALT1), PT_SUNW_EH_FRAME }, 254*9085SAli.Bahrami@Sun.COM 2555411Sab196087 { MSG_ORIG(MSG_PT_SUNWBSS), PT_SUNWBSS }, 2565411Sab196087 { MSG_ORIG(MSG_PT_SUNWBSS_ALT1), PT_SUNWBSS }, 2575411Sab196087 2585411Sab196087 { MSG_ORIG(MSG_PT_SUNWSTACK), PT_SUNWSTACK }, 2595411Sab196087 { MSG_ORIG(MSG_PT_SUNWSTACK_ALT1), PT_SUNWSTACK }, 2605411Sab196087 2615411Sab196087 { MSG_ORIG(MSG_PT_SUNWDTRACE), PT_SUNWDTRACE }, 2625411Sab196087 { MSG_ORIG(MSG_PT_SUNWDTRACE_ALT1), PT_SUNWDTRACE }, 2635411Sab196087 2645411Sab196087 { MSG_ORIG(MSG_PT_SUNWCAP), PT_SUNWCAP }, 2655411Sab196087 { MSG_ORIG(MSG_PT_SUNWCAP_ALT1), PT_SUNWCAP }, 2665411Sab196087 2675411Sab196087 { NULL } 2685411Sab196087 }; 2695411Sab196087 2705411Sab196087 2715411Sab196087 2725411Sab196087 2734168Sab196087 2741618Srie const char * 2751618Srie _elfdump_msg(Msg mid) 2761618Srie { 2771618Srie return (gettext(MSG_ORIG(mid))); 2781618Srie } 2791618Srie 2801618Srie /* 2811618Srie * Determine whether a symbol name should be demangled. 2821618Srie */ 2831618Srie const char * 2841618Srie demangle(const char *name, uint_t flags) 2851618Srie { 2865411Sab196087 if (flags & FLG_CTL_DEMANGLE) 2871618Srie return (Elf_demangle_name(name)); 2881618Srie else 2891618Srie return ((char *)name); 2901618Srie } 2911618Srie 2921618Srie /* 2931618Srie * Define our own standard error routine. 2941618Srie */ 2951618Srie void 2961618Srie failure(const char *file, const char *func) 2971618Srie { 2981618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_FAILURE), 2991618Srie file, func, elf_errmsg(elf_errno())); 3001618Srie } 3011618Srie 3021618Srie /* 3031618Srie * The full usage message 3041618Srie */ 3051618Srie static void 3061618Srie detail_usage() 3071618Srie { 3081618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL1)); 3091618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL2)); 3101618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL3)); 3111618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL4)); 3121618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL5)); 3131618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL6)); 3141618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL7)); 3151618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL8)); 3161618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL9)); 3171618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL10)); 3181618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL11)); 3191618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL12)); 3201618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL13)); 3211618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL14)); 3221618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL15)); 3231618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL16)); 3241618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL17)); 3251618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL18)); 3261618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL19)); 3271618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL20)); 3283492Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL21)); 3294168Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL22)); 3304168Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL23)); 3314665Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL24)); 3325411Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL25)); 3334168Sab196087 } 3344168Sab196087 3354168Sab196087 /* 3366635Sab196087 * Output a block of raw data as hex bytes. Each row is given 3376635Sab196087 * the index of the first byte in the row. 3386635Sab196087 * 3396635Sab196087 * entry: 3406635Sab196087 * data - Pointer to first byte of data to be displayed 3416635Sab196087 * n - # of bytes of data 3426635Sab196087 * prefix - String to be output before each line. Useful 3436635Sab196087 * for indenting output. 3446635Sab196087 * bytes_per_col - # of space separated bytes to output 3456635Sab196087 * in each column. 3466635Sab196087 * col_per_row - # of columns to output per row 3476635Sab196087 * 3486635Sab196087 * exit: 3496635Sab196087 * The formatted data has been sent to stdout. Each row of output 3506635Sab196087 * shows (bytes_per_col * col_per_row) bytes of data. 3516635Sab196087 */ 3526635Sab196087 void 353*9085SAli.Bahrami@Sun.COM dump_hex_bytes(const void *data, size_t n, int indent, 3546635Sab196087 int bytes_per_col, int col_per_row) 3556635Sab196087 { 356*9085SAli.Bahrami@Sun.COM const uchar_t *ldata = data; 3576635Sab196087 int bytes_per_row = bytes_per_col * col_per_row; 3586635Sab196087 int ndx, byte, word; 3596635Sab196087 char string[128], *str = string; 3606635Sab196087 char index[MAXNDXSIZE]; 3616635Sab196087 int index_width; 3626635Sab196087 int sp_prefix = 0; 3636635Sab196087 3646635Sab196087 3656635Sab196087 /* 3666635Sab196087 * Determine the width to use for the index string. We follow 3676635Sab196087 * 8-byte tab rules, but don't use an actual \t character so 3686635Sab196087 * that the output can be arbitrarily shifted without odd 3696635Sab196087 * tab effects, and so that all the columns line up no matter 3706635Sab196087 * how many lines of output are produced. 3716635Sab196087 */ 3726635Sab196087 ndx = n / bytes_per_row; 3736635Sab196087 (void) snprintf(index, sizeof (index), 3746635Sab196087 MSG_ORIG(MSG_FMT_INDEX2), EC_WORD(ndx)); 3756635Sab196087 index_width = strlen(index); 3766635Sab196087 index_width = S_ROUND(index_width, 8); 3776635Sab196087 378*9085SAli.Bahrami@Sun.COM for (ndx = byte = word = 0; n > 0; n--, ldata++) { 3796635Sab196087 while (sp_prefix-- > 0) 3806635Sab196087 *str++ = ' '; 3816635Sab196087 3826635Sab196087 (void) snprintf(str, sizeof (string), 383*9085SAli.Bahrami@Sun.COM MSG_ORIG(MSG_HEXDUMP_TOK), (int)*ldata); 3846635Sab196087 str += 2; 3856635Sab196087 sp_prefix = 1; 3866635Sab196087 3876635Sab196087 if (++byte == bytes_per_col) { 3886635Sab196087 sp_prefix += 2; 3896635Sab196087 word++; 3906635Sab196087 byte = 0; 3916635Sab196087 } 3926635Sab196087 if (word == col_per_row) { 3936635Sab196087 *str = '\0'; 3946635Sab196087 (void) snprintf(index, sizeof (index), 3956635Sab196087 MSG_ORIG(MSG_FMT_INDEX2), EC_WORD(ndx)); 3966635Sab196087 dbg_print(0, MSG_ORIG(MSG_HEXDUMP_ROW), 3976635Sab196087 indent, MSG_ORIG(MSG_STR_EMPTY), 3986635Sab196087 index_width, index, string); 3996635Sab196087 sp_prefix = 0; 4006635Sab196087 word = 0; 4016635Sab196087 ndx += bytes_per_row; 4026635Sab196087 str = string; 4036635Sab196087 } 4046635Sab196087 } 4056635Sab196087 if (byte || word) { 4066635Sab196087 *str = '\0'; /* */ 4076635Sab196087 (void) snprintf(index, sizeof (index), 4086635Sab196087 MSG_ORIG(MSG_FMT_INDEX2), EC_WORD(ndx)); 4096635Sab196087 dbg_print(0, MSG_ORIG(MSG_HEXDUMP_ROW), indent, 4106635Sab196087 MSG_ORIG(MSG_STR_EMPTY), index_width, index, string); 4116635Sab196087 } 4126635Sab196087 } 4136635Sab196087 4146635Sab196087 /* 4154168Sab196087 * Convert the ASCII representation of an index, or index range, into 4164168Sab196087 * binary form, and store it in rec: 4174168Sab196087 * 4184168Sab196087 * index: An positive or 0 valued integer 4194168Sab196087 * range: Two indexes, separated by a ':' character, denoting 4204168Sab196087 * a range of allowed values. If the second value is omitted, 4214168Sab196087 * any values equal to or greater than the first will match. 4224168Sab196087 * 4234168Sab196087 * exit: 4245411Sab196087 * On success, *rec is filled in with a MATCH_OPT_NDX or MATCH_OPT_RANGE 4254168Sab196087 * value, and this function returns (1). On failure, the contents 4264168Sab196087 * of *rec are undefined, and (0) is returned. 4274168Sab196087 */ 4284168Sab196087 int 4295411Sab196087 process_index_opt(const char *str, match_rec_t *rec) 4304168Sab196087 { 4314168Sab196087 #define SKIP_BLANK for (; *str && isspace(*str); str++) 4324168Sab196087 4334168Sab196087 char *endptr; 4344168Sab196087 4354168Sab196087 rec->value.ndx.start = strtol(str, &endptr, 10); 4364168Sab196087 /* Value must use some of the input, and be 0 or positive */ 4374168Sab196087 if ((str == endptr) || (rec->value.ndx.start < 0)) 4384168Sab196087 return (0); 4394168Sab196087 str = endptr; 4404168Sab196087 4414168Sab196087 SKIP_BLANK; 4424168Sab196087 if (*str != ':') { 4435411Sab196087 rec->opt_type = MATCH_OPT_NDX; 4444168Sab196087 } else { 4454168Sab196087 str++; /* Skip the ':' */ 4465411Sab196087 rec->opt_type = MATCH_OPT_RANGE; 4474168Sab196087 SKIP_BLANK; 4484168Sab196087 if (*str == '\0') { 4494168Sab196087 rec->value.ndx.end = -1; /* Indicates "to end" */ 4504168Sab196087 } else { 4514168Sab196087 rec->value.ndx.end = strtol(str, &endptr, 10); 4524168Sab196087 if ((str == endptr) || (rec->value.ndx.end < 0)) 4534168Sab196087 return (0); 4544168Sab196087 str = endptr; 4554168Sab196087 SKIP_BLANK; 4564168Sab196087 } 4574168Sab196087 } 4584168Sab196087 4594168Sab196087 /* Syntax error if anything is left over */ 4604168Sab196087 if (*str != '\0') 4614168Sab196087 return (0); 4624168Sab196087 4634168Sab196087 return (1); 4644168Sab196087 4654168Sab196087 #undef SKIP_BLANK 4664168Sab196087 } 4674168Sab196087 4684168Sab196087 /* 4695411Sab196087 * Process the symbolic name to value mappings passed to the 4705411Sab196087 * atoui() function. 4715411Sab196087 * 4725411Sab196087 * entry: 4735411Sab196087 * sym - NULL terminated array of name->value mappings. 4745411Sab196087 * value - Address of variable to receive corresponding value. 4755411Sab196087 * 4765411Sab196087 * exit: 4775411Sab196087 * If a mapping is found, *value is set to it, and True is returned. 4785411Sab196087 * Otherwise False is returned. 4795411Sab196087 */ 4805411Sab196087 static int 4815411Sab196087 atoui_sym_process(const char *str, const atoui_sym_t *sym, uint32_t *value) 4825411Sab196087 { 4835411Sab196087 size_t cmp_len; 4845411Sab196087 const char *tail; 4855411Sab196087 4865411Sab196087 while (isspace(*str)) 4875411Sab196087 str++; 4885411Sab196087 4895411Sab196087 tail = str + strlen(str); 4905411Sab196087 while ((tail > str) && isspace(*(tail - 1))) 4915411Sab196087 tail--; 4925411Sab196087 4935411Sab196087 cmp_len = tail - str; 4945411Sab196087 4955411Sab196087 for (; sym->sym_name != NULL; sym++) { 4965411Sab196087 if ((strlen(sym->sym_name) == cmp_len) && 4975411Sab196087 (strncasecmp(sym->sym_name, str, cmp_len) == 0)) { 4985411Sab196087 *value = sym->sym_value; 4995411Sab196087 return (1); 5005411Sab196087 } 5015411Sab196087 } 5025411Sab196087 5035411Sab196087 /* No symbolic mapping was found */ 5045411Sab196087 return (0); 5055411Sab196087 } 5065411Sab196087 5075411Sab196087 5085411Sab196087 /* 5095411Sab196087 * Convert a string to a numeric value. Strings starting with '0' 5105411Sab196087 * are taken to be octal, those staring with '0x' are hex, and all 5115411Sab196087 * others are decimal. 5125411Sab196087 * 5135411Sab196087 * entry: 5145411Sab196087 * str - String to be converted 5155411Sab196087 * sym - NULL, or NULL terminated array of name/value pairs. 5165411Sab196087 * v - Address of variable to receive resulting value. 5175411Sab196087 * 5185411Sab196087 * exit: 5195411Sab196087 * On success, returns True (1) and *v is set to the value. 5205411Sab196087 * On failure, returns False (0) and *v is undefined. 5215411Sab196087 */ 5225411Sab196087 static int 5235411Sab196087 atoui(const char *str, const atoui_sym_t *sym, uint32_t *v) 5245411Sab196087 { 5255411Sab196087 char *endptr; 5265411Sab196087 5275411Sab196087 if (sym && atoui_sym_process(str, sym, v)) 5285411Sab196087 return (1); 5295411Sab196087 5305411Sab196087 *v = strtoull(str, &endptr, 0); 5315411Sab196087 5325411Sab196087 /* If the left over part contains anything but whitespace, fail */ 5335411Sab196087 for (; *endptr; endptr++) 5345411Sab196087 if (!isspace(*endptr)) 5355411Sab196087 return (0); 5365411Sab196087 return (1); 5375411Sab196087 } 5385411Sab196087 5395411Sab196087 /* 5405411Sab196087 * Called after getopt() processing is finished if there is a non-empty 5415411Sab196087 * match list. Prepares the matching code for use. 5425411Sab196087 * 5435411Sab196087 * exit: 5445411Sab196087 * Returns True (1) if no errors are encountered. Writes an 5455411Sab196087 * error string to stderr and returns False (0) otherwise. 5465411Sab196087 */ 5475411Sab196087 static int 5485411Sab196087 match_prepare(char *argv0, uint_t flags) 5495411Sab196087 { 5505411Sab196087 atoui_sym_t *sym; 5515411Sab196087 match_rec_t *list; 5525411Sab196087 const char *str; 5535411Sab196087 int minus_p = (flags & FLG_SHOW_PHDR) != 0; 5545411Sab196087 5555411Sab196087 /* 5565411Sab196087 * Flag ambiguous attempt to use match option with both -p and 5575411Sab196087 * and one or more section SHOW options. In this case, we 5585411Sab196087 * can't tell what type of item we're supposed to match against. 5595411Sab196087 */ 5605411Sab196087 if (minus_p && (flags & FLG_MASK_SHOW_SHDR)) { 5615411Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_AMBIG_MATCH), 5625411Sab196087 basename(argv0)); 5635411Sab196087 return (0); 5645411Sab196087 } 5655411Sab196087 5665411Sab196087 /* Set the match type, based on the presence of the -p option */ 5675411Sab196087 if (minus_p) { 5685411Sab196087 match_state.item_type = MATCH_ITEM_PT; 5695411Sab196087 sym = sym_pt; 5705411Sab196087 } else { 5715411Sab196087 match_state.item_type = MATCH_ITEM_SHT; 5725411Sab196087 sym = sym_sht; 5735411Sab196087 } 5745411Sab196087 5755411Sab196087 /* 5765411Sab196087 * Scan match list and perform any necessary fixups: 5775411Sab196087 * 5785411Sab196087 * MATCH_OPT_NAME: If -p is specified, convert MATCH_OPT_NAME (-N) 5795411Sab196087 * requests into MATCH_OPT_TYPE (-T). 5805411Sab196087 * 5815411Sab196087 * MATCH_OPT_TYPE: Now that we know item type we are matching 5825411Sab196087 * against, we can convert the string saved in the name 5835411Sab196087 * field during getopt() processing into an integer and 5845411Sab196087 * write it into the type field. 5855411Sab196087 */ 5865411Sab196087 for (list = match_state.list; list; list = list->next) { 5875411Sab196087 if ((list->opt_type == MATCH_OPT_NAME) && minus_p) 5885411Sab196087 list->opt_type = MATCH_OPT_TYPE; 5895411Sab196087 5905411Sab196087 if (list->opt_type != MATCH_OPT_TYPE) 5915411Sab196087 continue; 5925411Sab196087 5935411Sab196087 str = list->value.name; 5945411Sab196087 if (atoui(str, sym, &list->value.type) == 0) { 5955411Sab196087 const char *fmt = minus_p ? 5965411Sab196087 MSG_INTL(MSG_ERR_BAD_T_PT) : 5975411Sab196087 MSG_INTL(MSG_ERR_BAD_T_SHT); 5985411Sab196087 5995411Sab196087 (void) fprintf(stderr, fmt, basename(argv0), str); 6005411Sab196087 return (0); 6015411Sab196087 } 6025411Sab196087 } 6035411Sab196087 6045411Sab196087 return (1); 6055411Sab196087 } 6065411Sab196087 6075411Sab196087 6085411Sab196087 /* 6094168Sab196087 * Returns True (1) if the item with the given name or index should 6104168Sab196087 * be displayed, and False (0) if it should not be. 6114168Sab196087 * 6124168Sab196087 * entry: 6135411Sab196087 * match_flags - Bitmask specifying matching options, as described 6145411Sab196087 * in _elfdump.h. 6155411Sab196087 * name - If MATCH_F_NAME flag is set, name of item under 6165411Sab196087 * consideration. Otherwise ignored. 6174168Sab196087 * should not be considered. 6185411Sab196087 * ndx - If MATCH_F_NDX flag is set, index of item under consideration. 6195411Sab196087 * type - If MATCH_F_TYPE is set, type of item under consideration. 6205411Sab196087 * If MATCH_F_PHDR is set, this would be a program 6215411Sab196087 * header type (PT_). Otherwise, a section header type (SHT_). 6224168Sab196087 * 6234168Sab196087 * exit: 6244168Sab196087 * True will be returned if the given name/index matches those given 6255411Sab196087 * by one of the (-I, -N -T) command line options, or if no such option 6265411Sab196087 * was used in the command invocation and MATCH_F_STRICT is not 6275411Sab196087 * set. 6284168Sab196087 */ 6294168Sab196087 int 6305411Sab196087 match(match_flags_t match_flags, const char *name, uint_t ndx, uint_t type) 6314168Sab196087 { 6325411Sab196087 match_item_t item_type = (match_flags & MATCH_F_PHDR) ? 6335411Sab196087 MATCH_ITEM_PT : MATCH_ITEM_SHT; 6345411Sab196087 match_rec_t *list; 6354168Sab196087 6365411Sab196087 /* 6375411Sab196087 * If there is no match list, then we use the MATCH_F_STRICT 6385411Sab196087 * flag to decide what to return. In the strict case, we return 6395411Sab196087 * False (0), in the normal case, True (1). 6405411Sab196087 */ 6415411Sab196087 if (match_state.list == NULL) 6425411Sab196087 return ((match_flags & MATCH_F_STRICT) == 0); 6435411Sab196087 6445411Sab196087 /* 6455411Sab196087 * If item being checked is not the current match type, 6465411Sab196087 * then allow it. 6475411Sab196087 */ 6485411Sab196087 if (item_type != match_state.item_type) 6494168Sab196087 return (1); 6504168Sab196087 6514168Sab196087 /* Run through the match records and check for a hit */ 6525411Sab196087 for (list = match_state.list; list; list = list->next) { 6535411Sab196087 switch (list->opt_type) { 6545411Sab196087 case MATCH_OPT_NAME: 6555411Sab196087 if (((match_flags & MATCH_F_NAME) == 0) || 6565411Sab196087 (name == NULL)) 6575411Sab196087 break; 6585411Sab196087 if (strcmp(list->value.name, name) == 0) 6594168Sab196087 return (1); 6604168Sab196087 break; 6615411Sab196087 case MATCH_OPT_NDX: 6625411Sab196087 if ((match_flags & MATCH_F_NDX) && 6635411Sab196087 (ndx == list->value.ndx.start)) 6644168Sab196087 return (1); 6654168Sab196087 break; 6665411Sab196087 case MATCH_OPT_RANGE: 6674168Sab196087 /* 6684168Sab196087 * A range end value less than 0 means that any value 6694168Sab196087 * above the start is acceptible. 6704168Sab196087 */ 6715411Sab196087 if ((match_flags & MATCH_F_NDX) && 6725411Sab196087 (ndx >= list->value.ndx.start) && 6734168Sab196087 ((list->value.ndx.end < 0) || 6744168Sab196087 (ndx <= list->value.ndx.end))) 6754168Sab196087 return (1); 6764168Sab196087 break; 6775411Sab196087 6785411Sab196087 case MATCH_OPT_TYPE: 6795411Sab196087 if ((match_flags & MATCH_F_TYPE) && 6805411Sab196087 (type == list->value.type)) 6815411Sab196087 return (1); 6825411Sab196087 break; 6834168Sab196087 } 6844168Sab196087 } 6854168Sab196087 6864168Sab196087 /* Nothing matched */ 6874168Sab196087 return (0); 6884168Sab196087 } 6894168Sab196087 6904168Sab196087 /* 6915411Sab196087 * Add an entry to match_state.list for use by match(). This routine is for 6925411Sab196087 * use during getopt() processing. It should not be called once 6935411Sab196087 * match_prepare() has been called. 6944168Sab196087 * 6954168Sab196087 * Return True (1) for success. On failure, an error is written 6964168Sab196087 * to stderr, and False (0) is returned. 6974168Sab196087 */ 6984168Sab196087 static int 6995411Sab196087 add_match_record(char *argv0, match_rec_t *data) 7004168Sab196087 { 7015411Sab196087 match_rec_t *rec; 7025411Sab196087 match_rec_t *list; 7034168Sab196087 7044168Sab196087 if ((rec = malloc(sizeof (*rec))) == NULL) { 7054168Sab196087 int err = errno; 7064168Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC), 7074168Sab196087 basename(argv0), strerror(err)); 7084168Sab196087 return (0); 7094168Sab196087 } 7104168Sab196087 7114168Sab196087 *rec = *data; 7124168Sab196087 7135411Sab196087 /* Insert at end of match_state.list */ 7145411Sab196087 if (match_state.list == NULL) { 7155411Sab196087 match_state.list = rec; 7164168Sab196087 } else { 7175411Sab196087 for (list = match_state.list; list->next != NULL; 7185411Sab196087 list = list->next) 7194168Sab196087 ; 7204168Sab196087 list->next = rec; 7214168Sab196087 } 7224168Sab196087 7234168Sab196087 rec->next = NULL; 7244168Sab196087 return (1); 7251618Srie } 7261618Srie 7275411Sab196087 static int 7285411Sab196087 decide(const char *file, int fd, Elf *elf, uint_t flags, 7295411Sab196087 const char *wname, int wfd) 7301618Srie { 7315411Sab196087 int r; 7325411Sab196087 7331618Srie if (gelf_getclass(elf) == ELFCLASS64) 7345411Sab196087 r = regular64(file, fd, elf, flags, wname, wfd); 7351618Srie else 7365411Sab196087 r = regular32(file, fd, elf, flags, wname, wfd); 7375411Sab196087 7385411Sab196087 return (r); 7391618Srie } 7401618Srie 7415411Sab196087 static int 7425411Sab196087 archive(const char *file, int fd, Elf *elf, uint_t flags, 7435411Sab196087 const char *wname, int wfd) 7441618Srie { 7451618Srie Elf_Cmd cmd = ELF_C_READ; 7461618Srie Elf_Arhdr *arhdr; 747*9085SAli.Bahrami@Sun.COM Elf *_elf = NULL; 7481618Srie size_t ptr; 749*9085SAli.Bahrami@Sun.COM Elf_Arsym *arsym = NULL; 7501618Srie 7511618Srie /* 7523492Sab196087 * Determine if the archive symbol table itself is required. 7531618Srie */ 7545411Sab196087 if ((flags & FLG_SHOW_SYMBOLS) && 7555411Sab196087 match(MATCH_F_NAME, MSG_ORIG(MSG_ELF_ARSYM), 0, 0)) { 7561618Srie /* 7571618Srie * Get the archive symbol table. 7581618Srie */ 7591618Srie if (((arsym = elf_getarsym(elf, &ptr)) == 0) && elf_errno()) { 7601618Srie /* 7611618Srie * The arsym could be 0 even though there was no error. 7621618Srie * Print the error message only when there was 7631618Srie * real error from elf_getarsym(). 7641618Srie */ 7651618Srie failure(file, MSG_ORIG(MSG_ELF_GETARSYM)); 7665411Sab196087 return (0); 7671618Srie } 7681618Srie } 7691618Srie 7701618Srie /* 7711618Srie * Print the archive symbol table only when the archive symbol 7721618Srie * table exists and it was requested to print. 7731618Srie */ 7741618Srie if (arsym) { 7751618Srie size_t cnt; 7761618Srie char index[MAXNDXSIZE]; 7771618Srie size_t offset = 0, _offset = 0; 7781618Srie 7791618Srie /* 7801618Srie * Print out all the symbol entries. 7811618Srie */ 7821618Srie dbg_print(0, MSG_INTL(MSG_ARCHIVE_SYMTAB)); 7831618Srie dbg_print(0, MSG_INTL(MSG_ARCHIVE_FIELDS)); 7841618Srie 7851618Srie for (cnt = 0; cnt < ptr; cnt++, arsym++) { 7861618Srie /* 7871618Srie * For each object obtain an elf descriptor so that we 7881618Srie * can establish the members name. Note, we have had 7891618Srie * archives where the archive header has not been 7901618Srie * obtainable so be lenient with errors. 7911618Srie */ 7921618Srie if ((offset == 0) || ((arsym->as_off != 0) && 7931618Srie (arsym->as_off != _offset))) { 7941618Srie 7951618Srie if (_elf) 7961618Srie (void) elf_end(_elf); 7971618Srie 7981618Srie if (elf_rand(elf, arsym->as_off) != 7991618Srie arsym->as_off) { 8001618Srie failure(file, MSG_ORIG(MSG_ELF_RAND)); 801*9085SAli.Bahrami@Sun.COM arhdr = NULL; 8021618Srie } else if ((_elf = elf_begin(fd, 8031618Srie ELF_C_READ, elf)) == 0) { 8041618Srie failure(file, MSG_ORIG(MSG_ELF_BEGIN)); 805*9085SAli.Bahrami@Sun.COM arhdr = NULL; 8061618Srie } else if ((arhdr = elf_getarhdr(_elf)) == 0) { 8071618Srie failure(file, 8081618Srie MSG_ORIG(MSG_ELF_GETARHDR)); 809*9085SAli.Bahrami@Sun.COM arhdr = NULL; 8101618Srie } 8111618Srie 8121618Srie _offset = arsym->as_off; 8131618Srie if (offset == 0) 8141618Srie offset = _offset; 8151618Srie } 8161618Srie 8171618Srie (void) snprintf(index, MAXNDXSIZE, 8181618Srie MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(cnt)); 8191618Srie if (arsym->as_off) 8201618Srie dbg_print(0, MSG_ORIG(MSG_FMT_ARSYM1), index, 8211618Srie /* LINTED */ 8221618Srie (int)arsym->as_off, arhdr ? arhdr->ar_name : 8231618Srie MSG_INTL(MSG_STR_UNKNOWN), (arsym->as_name ? 8241618Srie demangle(arsym->as_name, flags) : 8251618Srie MSG_INTL(MSG_STR_NULL))); 8261618Srie else 8271618Srie dbg_print(0, MSG_ORIG(MSG_FMT_ARSYM2), index, 8281618Srie /* LINTED */ 8291618Srie (int)arsym->as_off); 8301618Srie } 8311618Srie 8321618Srie if (_elf) 8331618Srie (void) elf_end(_elf); 8341618Srie 8351618Srie /* 8361618Srie * If we only need the archive symbol table return. 8371618Srie */ 8385411Sab196087 if ((flags & FLG_SHOW_SYMBOLS) && 8395411Sab196087 match(MATCH_F_STRICT | MATCH_F_NAME, 8405411Sab196087 MSG_ORIG(MSG_ELF_ARSYM), -1, -1)) 8415411Sab196087 return (0); 8421618Srie 8431618Srie /* 8441618Srie * Reset elf descriptor in preparation for processing each 8451618Srie * member. 8461618Srie */ 8471618Srie if (offset) 8481618Srie (void) elf_rand(elf, offset); 8491618Srie } 8501618Srie 8511618Srie /* 8521618Srie * Process each object within the archive. 8531618Srie */ 8541618Srie while ((_elf = elf_begin(fd, cmd, elf)) != NULL) { 8551618Srie char name[MAXPATHLEN]; 8561618Srie 8571618Srie if ((arhdr = elf_getarhdr(_elf)) == NULL) { 8581618Srie failure(file, MSG_ORIG(MSG_ELF_GETARHDR)); 8595411Sab196087 return (0); 8601618Srie } 8611618Srie if (*arhdr->ar_name != '/') { 8621618Srie (void) snprintf(name, MAXPATHLEN, 8631618Srie MSG_ORIG(MSG_FMT_ARNAME), file, arhdr->ar_name); 8641618Srie dbg_print(0, MSG_ORIG(MSG_FMT_NLSTR), name); 8651618Srie 8661618Srie switch (elf_kind(_elf)) { 8671618Srie case ELF_K_AR: 8685411Sab196087 if (archive(name, fd, _elf, flags, 8695411Sab196087 wname, wfd) == 1) 8705411Sab196087 return (1); 8711618Srie break; 8721618Srie case ELF_K_ELF: 8735411Sab196087 if (decide(name, fd, _elf, flags, 8745411Sab196087 wname, wfd) == 1) 8755411Sab196087 return (1); 8761618Srie break; 8771618Srie default: 8781618Srie (void) fprintf(stderr, 8791618Srie MSG_INTL(MSG_ERR_BADFILE), name); 8801618Srie break; 8811618Srie } 8821618Srie } 8831618Srie 8841618Srie cmd = elf_next(_elf); 8851618Srie (void) elf_end(_elf); 8861618Srie } 8875411Sab196087 8885411Sab196087 return (0); 8891618Srie } 8901618Srie 8911618Srie int 8921618Srie main(int argc, char **argv, char **envp) 8931618Srie { 8941618Srie Elf *elf; 8951618Srie int var, fd, wfd = 0; 8965411Sab196087 char *wname = NULL; 8971618Srie uint_t flags = 0; 8985411Sab196087 match_rec_t match_data; 8995411Sab196087 int ret; 9001618Srie 9011618Srie /* 9021618Srie * If we're on a 64-bit kernel, try to exec a full 64-bit version of 9031618Srie * the binary. If successful, conv_check_native() won't return. 9041618Srie */ 9052647Srie (void) conv_check_native(argv, envp); 9061618Srie 9071618Srie /* 9081618Srie * Establish locale. 9091618Srie */ 9101618Srie (void) setlocale(LC_MESSAGES, MSG_ORIG(MSG_STR_EMPTY)); 9111618Srie (void) textdomain(MSG_ORIG(MSG_SUNW_OST_SGS)); 9121618Srie 9131618Srie (void) setvbuf(stdout, NULL, _IOLBF, 0); 9141618Srie (void) setvbuf(stderr, NULL, _IOLBF, 0); 9151618Srie 9161618Srie opterr = 0; 9171618Srie while ((var = getopt(argc, argv, MSG_ORIG(MSG_STR_OPTIONS))) != EOF) { 9181618Srie switch (var) { 9191618Srie case 'C': 9205411Sab196087 flags |= FLG_CTL_DEMANGLE; 9211618Srie break; 9221618Srie case 'c': 9235411Sab196087 flags |= FLG_SHOW_SHDR; 9241618Srie break; 9251618Srie case 'd': 9265411Sab196087 flags |= FLG_SHOW_DYNAMIC; 9271618Srie break; 9281618Srie case 'e': 9295411Sab196087 flags |= FLG_SHOW_EHDR; 9301618Srie break; 9311618Srie case 'G': 9325411Sab196087 flags |= FLG_SHOW_GOT; 9331618Srie break; 9341618Srie case 'g': 9355411Sab196087 flags |= FLG_SHOW_GROUP; 9361618Srie break; 9371618Srie case 'H': 9385411Sab196087 flags |= FLG_SHOW_CAP; 9391618Srie break; 9401618Srie case 'h': 9415411Sab196087 flags |= FLG_SHOW_HASH; 9421618Srie break; 9434168Sab196087 case 'I': 9445411Sab196087 if (!process_index_opt(optarg, &match_data)) 9455411Sab196087 goto usage_brief; 9464168Sab196087 if (!add_match_record(argv[0], &match_data)) 9474168Sab196087 return (1); 9485411Sab196087 flags |= FLG_CTL_MATCH; 9494168Sab196087 break; 9501618Srie case 'i': 9515411Sab196087 flags |= FLG_SHOW_INTERP; 9521618Srie break; 9531618Srie case 'k': 9545411Sab196087 flags |= FLG_CALC_CHECKSUM; 9551618Srie break; 9561618Srie case 'l': 9575411Sab196087 flags |= FLG_CTL_LONGNAME; 9581618Srie break; 9591618Srie case 'm': 9605411Sab196087 flags |= FLG_SHOW_MOVE; 9611618Srie break; 9621618Srie case 'N': 9635411Sab196087 match_data.opt_type = MATCH_OPT_NAME; 9644168Sab196087 match_data.value.name = optarg; 9654168Sab196087 if (!add_match_record(argv[0], &match_data)) 9664168Sab196087 return (1); 9675411Sab196087 flags |= FLG_CTL_MATCH; 9681618Srie break; 9691618Srie case 'n': 9705411Sab196087 flags |= FLG_SHOW_NOTE; 9711618Srie break; 9724665Sab196087 case 'P': 9735411Sab196087 flags |= FLG_CTL_FAKESHDR; 9744665Sab196087 break; 9751618Srie case 'p': 9765411Sab196087 flags |= FLG_SHOW_PHDR; 9771618Srie break; 9781618Srie case 'r': 9795411Sab196087 flags |= FLG_SHOW_RELOC; 9801618Srie break; 9813492Sab196087 case 'S': 9825411Sab196087 flags |= FLG_SHOW_SORT; 9833492Sab196087 break; 9841618Srie case 's': 9855411Sab196087 flags |= FLG_SHOW_SYMBOLS; 9865411Sab196087 break; 9875411Sab196087 case 'T': 9885411Sab196087 /* 9895411Sab196087 * We can't evaluate the value yet, because 9905411Sab196087 * we need to know if -p is used or not in 9915411Sab196087 * order to tell if we're seeing section header 9925411Sab196087 * or program header types. So, we save the 9935411Sab196087 * string in the name field, and then convert 9945411Sab196087 * it to a type integer in a following pass. 9955411Sab196087 */ 9965411Sab196087 match_data.opt_type = MATCH_OPT_TYPE; 9975411Sab196087 match_data.value.name = optarg; 9985411Sab196087 if (!add_match_record(argv[0], &match_data)) 9995411Sab196087 return (1); 10005411Sab196087 flags |= FLG_CTL_MATCH; 10011618Srie break; 10021618Srie case 'u': 10035411Sab196087 flags |= FLG_SHOW_UNWIND; 10041618Srie break; 10051618Srie case 'v': 10065411Sab196087 flags |= FLG_SHOW_VERSIONS; 10071618Srie break; 10081618Srie case 'w': 10091618Srie wname = optarg; 10101618Srie break; 10111618Srie case 'y': 10125411Sab196087 flags |= FLG_SHOW_SYMINFO; 10131618Srie break; 10141618Srie case '?': 10151618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF), 10161618Srie basename(argv[0])); 10171618Srie detail_usage(); 10181618Srie return (1); 10191618Srie default: 10201618Srie break; 10211618Srie } 10221618Srie } 10231618Srie 10245411Sab196087 /* -p and -w are mutually exclusive. -w only works with sections */ 10255411Sab196087 if (((flags & FLG_SHOW_PHDR) != 0) && (wname != NULL)) 10265411Sab196087 goto usage_brief; 10275411Sab196087 10285411Sab196087 /* If a match argument is present, prepare the match state */ 10295411Sab196087 if ((match_state.list != NULL) && (match_prepare(argv[0], flags) == 0)) 10305411Sab196087 return (1); 10315411Sab196087 10321618Srie /* 10335411Sab196087 * Decide what to do if no options specifying something to 10345411Sab196087 * show or do are present. 10355411Sab196087 * 10365411Sab196087 * If there is no -w and no match options, then we will set all 10375411Sab196087 * the show flags, causing a full display of everything in the 10385411Sab196087 * file that we know how to handle. 10395411Sab196087 * 10405411Sab196087 * Otherwise, if there is no match list, we generate a usage 10415411Sab196087 * error and quit. 10425411Sab196087 * 10435411Sab196087 * In the case where there is a match list, we go ahead and call 10445411Sab196087 * regular() anyway, leaving it to decide what to do. If -w is 10455411Sab196087 * present, regular() will use the match list to handle it. 10465411Sab196087 * In addition, in the absence of explicit show/calc flags, regular() 10475411Sab196087 * will compare the section headers to the match list and use 10485411Sab196087 * that to generate the FLG_ bits that will display the information 10495411Sab196087 * specified by the match list. 10501618Srie */ 10515411Sab196087 if ((flags & ~FLG_MASK_CTL) == 0) { 10525411Sab196087 if (!wname && (match_state.list == NULL)) 10535411Sab196087 flags |= FLG_MASK_SHOW; 10545411Sab196087 else if (match_state.list == NULL) 10555411Sab196087 goto usage_brief; 10561618Srie } 10571618Srie 10585411Sab196087 /* There needs to be at least 1 filename left following the options */ 10595411Sab196087 if ((var = argc - optind) == 0) 10605411Sab196087 goto usage_brief; 10611618Srie 10621618Srie /* 10631618Srie * If the -l/-C option is specified, set up the liblddbg.so. 10641618Srie */ 10655411Sab196087 if (flags & FLG_CTL_LONGNAME) 10661618Srie dbg_desc->d_extra |= DBG_E_LONG; 10675411Sab196087 if (flags & FLG_CTL_DEMANGLE) 10681618Srie dbg_desc->d_extra |= DBG_E_DEMANGLE; 10691618Srie 10701618Srie /* 10711618Srie * If the -w option has indicated an output file open it. It's 10721618Srie * arguable whether this option has much use when multiple files are 10731618Srie * being processed. 10745411Sab196087 * 10755411Sab196087 * If wname is non-NULL, we know that -p was not specified, due 10765411Sab196087 * to the test above. 10771618Srie */ 10781618Srie if (wname) { 10791618Srie if ((wfd = open(wname, (O_RDWR | O_CREAT | O_TRUNC), 10801618Srie 0666)) < 0) { 10811618Srie int err = errno; 10821618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_OPEN), 10831618Srie wname, strerror(err)); 10845411Sab196087 return (1); 10851618Srie } 10861618Srie } 10871618Srie 10881618Srie /* 10895411Sab196087 * Open the input file, initialize the elf interface, and 10905411Sab196087 * process it. 10911618Srie */ 10925411Sab196087 ret = 0; 10935411Sab196087 for (; (optind < argc) && (ret == 0); optind++) { 10941618Srie const char *file = argv[optind]; 10951618Srie 10961618Srie if ((fd = open(argv[optind], O_RDONLY)) == -1) { 10971618Srie int err = errno; 10981618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_OPEN), 10991618Srie file, strerror(err)); 11001618Srie continue; 11011618Srie } 11021618Srie (void) elf_version(EV_CURRENT); 11031618Srie if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { 11041618Srie failure(file, MSG_ORIG(MSG_ELF_BEGIN)); 11051618Srie (void) close(fd); 11061618Srie continue; 11071618Srie } 11081618Srie 11091618Srie if (var > 1) 11101618Srie dbg_print(0, MSG_ORIG(MSG_FMT_NLSTRNL), file); 11111618Srie 11121618Srie switch (elf_kind(elf)) { 11131618Srie case ELF_K_AR: 11145411Sab196087 ret = archive(file, fd, elf, flags, wname, wfd); 11151618Srie break; 11161618Srie case ELF_K_ELF: 11175411Sab196087 ret = decide(file, fd, elf, flags, wname, wfd); 11181618Srie break; 11191618Srie default: 11201618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADFILE), file); 11211618Srie break; 11221618Srie } 11231618Srie 11241618Srie (void) close(fd); 11251618Srie (void) elf_end(elf); 11261618Srie } 11271618Srie 11281618Srie if (wfd) 11291618Srie (void) close(wfd); 11305411Sab196087 return (ret); 11315411Sab196087 11325411Sab196087 usage_brief: 11335411Sab196087 /* Control comes here for a simple usage message and exit */ 11345411Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF), 11355411Sab196087 basename(argv[0])); 11365411Sab196087 return (1); 11375411Sab196087 11381618Srie } 1139