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 /* 233492Sab196087 * Copyright 2007 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> 34*4168Sab196087 #include <stdlib.h> 35*4168Sab196087 #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> 491618Srie 504063Sab196087 const Cache cache_init = {NULL, NULL, NULL, NULL, 0}; 511618Srie 52*4168Sab196087 53*4168Sab196087 54*4168Sab196087 /* MATCH is used to retain information about -N and -I options */ 55*4168Sab196087 typedef enum { 56*4168Sab196087 MATCH_T_NAME, /* Record contains a name */ 57*4168Sab196087 MATCH_T_NDX, /* Record contains a single index */ 58*4168Sab196087 MATCH_T_RANGE /* Record contains an index range */ 59*4168Sab196087 } MATCH_T; 60*4168Sab196087 61*4168Sab196087 typedef struct _match { 62*4168Sab196087 struct _match *next; /* Pointer to next item in list */ 63*4168Sab196087 MATCH_T type; 64*4168Sab196087 union { 65*4168Sab196087 const char *name; /* MATCH_T_NAME */ 66*4168Sab196087 struct { /* MATCH_T_NDX and MATCH_T_RANGE */ 67*4168Sab196087 int start; 68*4168Sab196087 int end; /* Only for MATCH_T_RANGE */ 69*4168Sab196087 } ndx; 70*4168Sab196087 } value; 71*4168Sab196087 } MATCH; 72*4168Sab196087 73*4168Sab196087 /* List of MATCH records used by match() to implement -N and -I options */ 74*4168Sab196087 static MATCH *match_list = NULL; 75*4168Sab196087 761618Srie const char * 771618Srie _elfdump_msg(Msg mid) 781618Srie { 791618Srie return (gettext(MSG_ORIG(mid))); 801618Srie } 811618Srie 821618Srie /* 831618Srie * Determine whether a symbol name should be demangled. 841618Srie */ 851618Srie const char * 861618Srie demangle(const char *name, uint_t flags) 871618Srie { 881618Srie if (flags & FLG_DEMANGLE) 891618Srie return (Elf_demangle_name(name)); 901618Srie else 911618Srie return ((char *)name); 921618Srie } 931618Srie 941618Srie /* 951618Srie * Define our own standard error routine. 961618Srie */ 971618Srie void 981618Srie failure(const char *file, const char *func) 991618Srie { 1001618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_FAILURE), 1011618Srie file, func, elf_errmsg(elf_errno())); 1021618Srie } 1031618Srie 1041618Srie /* 1051618Srie * The full usage message 1061618Srie */ 1071618Srie static void 1081618Srie detail_usage() 1091618Srie { 1101618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL1)); 1111618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL2)); 1121618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL3)); 1131618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL4)); 1141618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL5)); 1151618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL6)); 1161618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL7)); 1171618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL8)); 1181618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL9)); 1191618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL10)); 1201618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL11)); 1211618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL12)); 1221618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL13)); 1231618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL14)); 1241618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL15)); 1251618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL16)); 1261618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL17)); 1271618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL18)); 1281618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL19)); 1291618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL20)); 1303492Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL21)); 131*4168Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL22)); 132*4168Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL23)); 133*4168Sab196087 } 134*4168Sab196087 135*4168Sab196087 /* 136*4168Sab196087 * Convert the ASCII representation of an index, or index range, into 137*4168Sab196087 * binary form, and store it in rec: 138*4168Sab196087 * 139*4168Sab196087 * index: An positive or 0 valued integer 140*4168Sab196087 * range: Two indexes, separated by a ':' character, denoting 141*4168Sab196087 * a range of allowed values. If the second value is omitted, 142*4168Sab196087 * any values equal to or greater than the first will match. 143*4168Sab196087 * 144*4168Sab196087 * exit: 145*4168Sab196087 * On success, *rec is filled in with a MATCH_T_NDX or MATCH_T_RANGE 146*4168Sab196087 * value, and this function returns (1). On failure, the contents 147*4168Sab196087 * of *rec are undefined, and (0) is returned. 148*4168Sab196087 */ 149*4168Sab196087 int 150*4168Sab196087 process_index_opt(const char *str, MATCH *rec) 151*4168Sab196087 { 152*4168Sab196087 #define SKIP_BLANK for (; *str && isspace(*str); str++) 153*4168Sab196087 154*4168Sab196087 char *endptr; 155*4168Sab196087 156*4168Sab196087 rec->value.ndx.start = strtol(str, &endptr, 10); 157*4168Sab196087 /* Value must use some of the input, and be 0 or positive */ 158*4168Sab196087 if ((str == endptr) || (rec->value.ndx.start < 0)) 159*4168Sab196087 return (0); 160*4168Sab196087 str = endptr; 161*4168Sab196087 162*4168Sab196087 SKIP_BLANK; 163*4168Sab196087 if (*str != ':') { 164*4168Sab196087 rec->type = MATCH_T_NDX; 165*4168Sab196087 } else { 166*4168Sab196087 str++; /* Skip the ':' */ 167*4168Sab196087 rec->type = MATCH_T_RANGE; 168*4168Sab196087 SKIP_BLANK; 169*4168Sab196087 if (*str == '\0') { 170*4168Sab196087 rec->value.ndx.end = -1; /* Indicates "to end" */ 171*4168Sab196087 } else { 172*4168Sab196087 rec->value.ndx.end = strtol(str, &endptr, 10); 173*4168Sab196087 if ((str == endptr) || (rec->value.ndx.end < 0)) 174*4168Sab196087 return (0); 175*4168Sab196087 str = endptr; 176*4168Sab196087 SKIP_BLANK; 177*4168Sab196087 } 178*4168Sab196087 } 179*4168Sab196087 180*4168Sab196087 /* Syntax error if anything is left over */ 181*4168Sab196087 if (*str != '\0') 182*4168Sab196087 return (0); 183*4168Sab196087 184*4168Sab196087 return (1); 185*4168Sab196087 186*4168Sab196087 #undef SKIP_BLANK 187*4168Sab196087 } 188*4168Sab196087 189*4168Sab196087 /* 190*4168Sab196087 * Returns True (1) if the item with the given name or index should 191*4168Sab196087 * be displayed, and False (0) if it should not be. 192*4168Sab196087 * 193*4168Sab196087 * entry: 194*4168Sab196087 * strict - A strict match requires an explicit match to 195*4168Sab196087 * a user specified -I or -N option. A non-strict match 196*4168Sab196087 * succeeds if the match list is empty. 197*4168Sab196087 * name - Name of item under consideration, or NULL if the name 198*4168Sab196087 * should not be considered. 199*4168Sab196087 * ndx - if (ndx >= 0) index of item under consideration. 200*4168Sab196087 * A negative value indicates that the item has no index. 201*4168Sab196087 * 202*4168Sab196087 * exit: 203*4168Sab196087 * True will be returned if the given name/index matches those given 204*4168Sab196087 * by one of the -N or -I command line options, or if no such option 205*4168Sab196087 * was used in the command invocation. 206*4168Sab196087 */ 207*4168Sab196087 int 208*4168Sab196087 match(int strict, const char *name, int ndx) 209*4168Sab196087 { 210*4168Sab196087 MATCH *list; 211*4168Sab196087 212*4168Sab196087 /* If no match options were specified, allow everything */ 213*4168Sab196087 if (!strict && (match_list == NULL)) 214*4168Sab196087 return (1); 215*4168Sab196087 216*4168Sab196087 /* Run through the match records and check for a hit */ 217*4168Sab196087 for (list = match_list; list; list = list->next) { 218*4168Sab196087 switch (list->type) { 219*4168Sab196087 case MATCH_T_NAME: 220*4168Sab196087 if ((name != NULL) && 221*4168Sab196087 (strcmp(list->value.name, name) == 0)) 222*4168Sab196087 return (1); 223*4168Sab196087 break; 224*4168Sab196087 case MATCH_T_NDX: 225*4168Sab196087 if (ndx == list->value.ndx.start) 226*4168Sab196087 return (1); 227*4168Sab196087 break; 228*4168Sab196087 case MATCH_T_RANGE: 229*4168Sab196087 /* 230*4168Sab196087 * A range end value less than 0 means that any value 231*4168Sab196087 * above the start is acceptible. 232*4168Sab196087 */ 233*4168Sab196087 if ((ndx >= list->value.ndx.start) && 234*4168Sab196087 ((list->value.ndx.end < 0) || 235*4168Sab196087 (ndx <= list->value.ndx.end))) 236*4168Sab196087 return (1); 237*4168Sab196087 break; 238*4168Sab196087 } 239*4168Sab196087 } 240*4168Sab196087 241*4168Sab196087 /* Nothing matched */ 242*4168Sab196087 return (0); 243*4168Sab196087 } 244*4168Sab196087 245*4168Sab196087 /* 246*4168Sab196087 * Add an entry to match_list for use by match(). 247*4168Sab196087 * 248*4168Sab196087 * Return True (1) for success. On failure, an error is written 249*4168Sab196087 * to stderr, and False (0) is returned. 250*4168Sab196087 */ 251*4168Sab196087 static int 252*4168Sab196087 add_match_record(char *argv0, MATCH *data) 253*4168Sab196087 { 254*4168Sab196087 MATCH *rec; 255*4168Sab196087 MATCH *list; 256*4168Sab196087 257*4168Sab196087 if ((rec = malloc(sizeof (*rec))) == NULL) { 258*4168Sab196087 int err = errno; 259*4168Sab196087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC), 260*4168Sab196087 basename(argv0), strerror(err)); 261*4168Sab196087 return (0); 262*4168Sab196087 } 263*4168Sab196087 264*4168Sab196087 *rec = *data; 265*4168Sab196087 266*4168Sab196087 /* Insert at end of match_list */ 267*4168Sab196087 if (match_list == NULL) { 268*4168Sab196087 match_list = rec; 269*4168Sab196087 } else { 270*4168Sab196087 for (list = match_list; list->next != NULL; list = list->next) 271*4168Sab196087 ; 272*4168Sab196087 list->next = rec; 273*4168Sab196087 } 274*4168Sab196087 275*4168Sab196087 rec->next = NULL; 276*4168Sab196087 return (1); 2771618Srie } 2781618Srie 2791618Srie static void 280*4168Sab196087 decide(const char *file, Elf *elf, uint_t flags, int wfd) 2811618Srie { 2821618Srie if (gelf_getclass(elf) == ELFCLASS64) 283*4168Sab196087 regular64(file, elf, flags, wfd); 2841618Srie else 285*4168Sab196087 regular32(file, elf, flags, wfd); 2861618Srie } 2871618Srie 2881618Srie static void 289*4168Sab196087 archive(const char *file, int fd, Elf *elf, uint_t flags, int wfd) 2901618Srie { 2911618Srie Elf_Cmd cmd = ELF_C_READ; 2921618Srie Elf_Arhdr *arhdr; 2931618Srie Elf *_elf = 0; 2941618Srie size_t ptr; 2951618Srie Elf_Arsym *arsym = 0; 2961618Srie 2971618Srie /* 2983492Sab196087 * Determine if the archive symbol table itself is required. 2991618Srie */ 300*4168Sab196087 if ((flags & FLG_SYMBOLS) && match(0, MSG_ORIG(MSG_ELF_ARSYM), -1)) { 3011618Srie /* 3021618Srie * Get the archive symbol table. 3031618Srie */ 3041618Srie if (((arsym = elf_getarsym(elf, &ptr)) == 0) && elf_errno()) { 3051618Srie /* 3061618Srie * The arsym could be 0 even though there was no error. 3071618Srie * Print the error message only when there was 3081618Srie * real error from elf_getarsym(). 3091618Srie */ 3101618Srie failure(file, MSG_ORIG(MSG_ELF_GETARSYM)); 3111618Srie return; 3121618Srie } 3131618Srie } 3141618Srie 3151618Srie /* 3161618Srie * Print the archive symbol table only when the archive symbol 3171618Srie * table exists and it was requested to print. 3181618Srie */ 3191618Srie if (arsym) { 3201618Srie size_t cnt; 3211618Srie char index[MAXNDXSIZE]; 3221618Srie size_t offset = 0, _offset = 0; 3231618Srie 3241618Srie /* 3251618Srie * Print out all the symbol entries. 3261618Srie */ 3271618Srie dbg_print(0, MSG_INTL(MSG_ARCHIVE_SYMTAB)); 3281618Srie dbg_print(0, MSG_INTL(MSG_ARCHIVE_FIELDS)); 3291618Srie 3301618Srie for (cnt = 0; cnt < ptr; cnt++, arsym++) { 3311618Srie /* 3321618Srie * For each object obtain an elf descriptor so that we 3331618Srie * can establish the members name. Note, we have had 3341618Srie * archives where the archive header has not been 3351618Srie * obtainable so be lenient with errors. 3361618Srie */ 3371618Srie if ((offset == 0) || ((arsym->as_off != 0) && 3381618Srie (arsym->as_off != _offset))) { 3391618Srie 3401618Srie if (_elf) 3411618Srie (void) elf_end(_elf); 3421618Srie 3431618Srie if (elf_rand(elf, arsym->as_off) != 3441618Srie arsym->as_off) { 3451618Srie failure(file, MSG_ORIG(MSG_ELF_RAND)); 3461618Srie arhdr = 0; 3471618Srie } else if ((_elf = elf_begin(fd, 3481618Srie ELF_C_READ, elf)) == 0) { 3491618Srie failure(file, MSG_ORIG(MSG_ELF_BEGIN)); 3501618Srie arhdr = 0; 3511618Srie } else if ((arhdr = elf_getarhdr(_elf)) == 0) { 3521618Srie failure(file, 3531618Srie MSG_ORIG(MSG_ELF_GETARHDR)); 3541618Srie arhdr = 0; 3551618Srie } 3561618Srie 3571618Srie _offset = arsym->as_off; 3581618Srie if (offset == 0) 3591618Srie offset = _offset; 3601618Srie } 3611618Srie 3621618Srie (void) snprintf(index, MAXNDXSIZE, 3631618Srie MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(cnt)); 3641618Srie if (arsym->as_off) 3651618Srie dbg_print(0, MSG_ORIG(MSG_FMT_ARSYM1), index, 3661618Srie /* LINTED */ 3671618Srie (int)arsym->as_off, arhdr ? arhdr->ar_name : 3681618Srie MSG_INTL(MSG_STR_UNKNOWN), (arsym->as_name ? 3691618Srie demangle(arsym->as_name, flags) : 3701618Srie MSG_INTL(MSG_STR_NULL))); 3711618Srie else 3721618Srie dbg_print(0, MSG_ORIG(MSG_FMT_ARSYM2), index, 3731618Srie /* LINTED */ 3741618Srie (int)arsym->as_off); 3751618Srie } 3761618Srie 3771618Srie if (_elf) 3781618Srie (void) elf_end(_elf); 3791618Srie 3801618Srie /* 3811618Srie * If we only need the archive symbol table return. 3821618Srie */ 383*4168Sab196087 if ((flags & FLG_SYMBOLS) && 384*4168Sab196087 match(1, MSG_ORIG(MSG_ELF_ARSYM), -1)) 3851618Srie return; 3861618Srie 3871618Srie /* 3881618Srie * Reset elf descriptor in preparation for processing each 3891618Srie * member. 3901618Srie */ 3911618Srie if (offset) 3921618Srie (void) elf_rand(elf, offset); 3931618Srie } 3941618Srie 3951618Srie /* 3961618Srie * Process each object within the archive. 3971618Srie */ 3981618Srie while ((_elf = elf_begin(fd, cmd, elf)) != NULL) { 3991618Srie char name[MAXPATHLEN]; 4001618Srie 4011618Srie if ((arhdr = elf_getarhdr(_elf)) == NULL) { 4021618Srie failure(file, MSG_ORIG(MSG_ELF_GETARHDR)); 4031618Srie return; 4041618Srie } 4051618Srie if (*arhdr->ar_name != '/') { 4061618Srie (void) snprintf(name, MAXPATHLEN, 4071618Srie MSG_ORIG(MSG_FMT_ARNAME), file, arhdr->ar_name); 4081618Srie dbg_print(0, MSG_ORIG(MSG_FMT_NLSTR), name); 4091618Srie 4101618Srie switch (elf_kind(_elf)) { 4111618Srie case ELF_K_AR: 412*4168Sab196087 archive(name, fd, _elf, flags, wfd); 4131618Srie break; 4141618Srie case ELF_K_ELF: 415*4168Sab196087 decide(name, _elf, flags, wfd); 4161618Srie break; 4171618Srie default: 4181618Srie (void) fprintf(stderr, 4191618Srie MSG_INTL(MSG_ERR_BADFILE), name); 4201618Srie break; 4211618Srie } 4221618Srie } 4231618Srie 4241618Srie cmd = elf_next(_elf); 4251618Srie (void) elf_end(_elf); 4261618Srie } 4271618Srie } 4281618Srie 4291618Srie int 4301618Srie main(int argc, char **argv, char **envp) 4311618Srie { 4321618Srie Elf *elf; 4331618Srie int var, fd, wfd = 0; 434*4168Sab196087 char *wname = 0; 4351618Srie uint_t flags = 0; 436*4168Sab196087 MATCH match_data; 4371618Srie 4381618Srie /* 4391618Srie * If we're on a 64-bit kernel, try to exec a full 64-bit version of 4401618Srie * the binary. If successful, conv_check_native() won't return. 4411618Srie */ 4422647Srie (void) conv_check_native(argv, envp); 4431618Srie 4441618Srie /* 4451618Srie * Establish locale. 4461618Srie */ 4471618Srie (void) setlocale(LC_MESSAGES, MSG_ORIG(MSG_STR_EMPTY)); 4481618Srie (void) textdomain(MSG_ORIG(MSG_SUNW_OST_SGS)); 4491618Srie 4501618Srie (void) setvbuf(stdout, NULL, _IOLBF, 0); 4511618Srie (void) setvbuf(stderr, NULL, _IOLBF, 0); 4521618Srie 4531618Srie opterr = 0; 4541618Srie while ((var = getopt(argc, argv, MSG_ORIG(MSG_STR_OPTIONS))) != EOF) { 4551618Srie switch (var) { 4561618Srie case 'C': 4571618Srie flags |= FLG_DEMANGLE; 4581618Srie break; 4591618Srie case 'c': 4601618Srie flags |= FLG_SHDR; 4611618Srie break; 4621618Srie case 'd': 4631618Srie flags |= FLG_DYNAMIC; 4641618Srie break; 4651618Srie case 'e': 4661618Srie flags |= FLG_EHDR; 4671618Srie break; 4681618Srie case 'G': 4691618Srie flags |= FLG_GOT; 4701618Srie break; 4711618Srie case 'g': 4721618Srie flags |= FLG_GROUP; 4731618Srie break; 4741618Srie case 'H': 4751618Srie flags |= FLG_CAP; 4761618Srie break; 4771618Srie case 'h': 4781618Srie flags |= FLG_HASH; 4791618Srie break; 480*4168Sab196087 case 'I': 481*4168Sab196087 if (!process_index_opt(optarg, &match_data)) { 482*4168Sab196087 (void) fprintf(stderr, 483*4168Sab196087 MSG_INTL(MSG_USAGE_BRIEF), 484*4168Sab196087 basename(argv[0])); 485*4168Sab196087 return (1); 486*4168Sab196087 } 487*4168Sab196087 if (!add_match_record(argv[0], &match_data)) 488*4168Sab196087 return (1); 489*4168Sab196087 break; 4901618Srie case 'i': 4911618Srie flags |= FLG_INTERP; 4921618Srie break; 4931618Srie case 'k': 4941618Srie flags |= FLG_CHECKSUM; 4951618Srie break; 4961618Srie case 'l': 4971618Srie flags |= FLG_LONGNAME; 4981618Srie break; 4991618Srie case 'm': 5001618Srie flags |= FLG_MOVE; 5011618Srie break; 5021618Srie case 'N': 503*4168Sab196087 match_data.type = MATCH_T_NAME; 504*4168Sab196087 match_data.value.name = optarg; 505*4168Sab196087 if (!add_match_record(argv[0], &match_data)) 506*4168Sab196087 return (1); 5071618Srie break; 5081618Srie case 'n': 5091618Srie flags |= FLG_NOTE; 5101618Srie break; 5111618Srie case 'p': 5121618Srie flags |= FLG_PHDR; 5131618Srie break; 5141618Srie case 'r': 5151618Srie flags |= FLG_RELOC; 5161618Srie break; 5173492Sab196087 case 'S': 5183492Sab196087 flags |= FLG_SORT; 5193492Sab196087 break; 5201618Srie case 's': 5211618Srie flags |= FLG_SYMBOLS; 5221618Srie break; 5231618Srie case 'u': 5241618Srie flags |= FLG_UNWIND; 5251618Srie break; 5261618Srie case 'v': 5271618Srie flags |= FLG_VERSIONS; 5281618Srie break; 5291618Srie case 'w': 5301618Srie wname = optarg; 5311618Srie break; 5321618Srie case 'y': 5331618Srie flags |= FLG_SYMINFO; 5341618Srie break; 5351618Srie case '?': 5361618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF), 5371618Srie basename(argv[0])); 5381618Srie detail_usage(); 5391618Srie return (1); 5401618Srie default: 5411618Srie break; 5421618Srie } 5431618Srie } 5441618Srie 5451618Srie /* 5461618Srie * Validate any arguments. 5471618Srie */ 5481618Srie if ((flags & ~(FLG_DEMANGLE | FLG_LONGNAME)) == 0) { 549*4168Sab196087 if (!wname && (match_list == NULL)) { 5501618Srie flags |= FLG_EVERYTHING; 551*4168Sab196087 } else if (!wname || (match_list == NULL)) { 5521618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF), 5531618Srie basename(argv[0])); 5541618Srie return (1); 5551618Srie } 5561618Srie } 5571618Srie 5581618Srie if ((var = argc - optind) == 0) { 5591618Srie (void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF), 5601618Srie basename(argv[0])); 5611618Srie return (1); 5621618Srie } 5631618Srie 5641618Srie /* 5651618Srie * If the -l/-C option is specified, set up the liblddbg.so. 5661618Srie */ 5671618Srie if (flags & FLG_LONGNAME) 5681618Srie dbg_desc->d_extra |= DBG_E_LONG; 5691618Srie if (flags & FLG_DEMANGLE) 5701618Srie dbg_desc->d_extra |= DBG_E_DEMANGLE; 5711618Srie 5721618Srie /* 5731618Srie * If the -w option has indicated an output file open it. It's 5741618Srie * arguable whether this option has much use when multiple files are 5751618Srie * being processed. 5761618Srie */ 5771618Srie if (wname) { 5781618Srie if ((wfd = open(wname, (O_RDWR | O_CREAT | O_TRUNC), 5791618Srie 0666)) < 0) { 5801618Srie int err = errno; 5811618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_OPEN), 5821618Srie wname, strerror(err)); 5831618Srie wfd = 0; 5841618Srie } 5851618Srie } 5861618Srie 5871618Srie /* 5881618Srie * Open the input file and initialize the elf interface. 5891618Srie */ 5901618Srie for (; optind < argc; optind++) { 5911618Srie const char *file = argv[optind]; 5921618Srie 5931618Srie if ((fd = open(argv[optind], O_RDONLY)) == -1) { 5941618Srie int err = errno; 5951618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_OPEN), 5961618Srie file, strerror(err)); 5971618Srie continue; 5981618Srie } 5991618Srie (void) elf_version(EV_CURRENT); 6001618Srie if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { 6011618Srie failure(file, MSG_ORIG(MSG_ELF_BEGIN)); 6021618Srie (void) close(fd); 6031618Srie continue; 6041618Srie } 6051618Srie 6061618Srie if (var > 1) 6071618Srie dbg_print(0, MSG_ORIG(MSG_FMT_NLSTRNL), file); 6081618Srie 6091618Srie switch (elf_kind(elf)) { 6101618Srie case ELF_K_AR: 611*4168Sab196087 archive(file, fd, elf, flags, wfd); 6121618Srie break; 6131618Srie case ELF_K_ELF: 614*4168Sab196087 decide(file, elf, flags, wfd); 6151618Srie break; 6161618Srie default: 6171618Srie (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADFILE), file); 6181618Srie break; 6191618Srie } 6201618Srie 6211618Srie (void) close(fd); 6221618Srie (void) elf_end(elf); 6231618Srie } 6241618Srie 6251618Srie if (wfd) 6261618Srie (void) close(wfd); 6271618Srie return (0); 6281618Srie } 629