1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
  24  */
  25 
  26 /*
  27  * Dump an elf file.
  28  */
  29 #include        <sys/param.h>
  30 #include        <fcntl.h>
  31 #include        <stdio.h>
  32 #include        <stdlib.h>
  33 #include        <ctype.h>
  34 #include        <_libelf.h>
  35 #include        <link.h>
  36 #include        <stdarg.h>
  37 #include        <unistd.h>
  38 #include        <libgen.h>
  39 #include        <libintl.h>
  40 #include        <locale.h>
  41 #include        <errno.h>
  42 #include        <strings.h>
  43 #include        <debug.h>
  44 #include        <conv.h>
  45 #include        <msg.h>
  46 #include        <_elfdump.h>
  47 #include        <sys/elf_SPARC.h>
  48 #include        <sys/elf_amd64.h>
  49 
  50 
  51 const Cache     cache_init = {NULL, NULL, NULL, NULL, 0};
  52 
  53 
  54 
  55 /*
  56  * The -I, -N, and -T options are called "match options", because
  57  * they allow selecting the items to be displayed based on matching
  58  * their index, name, or type.
  59  *
  60  * The ELF information to which -I, -N, or -T are applied in
  61  * the current invocation is called the "match item".
  62  */
  63 typedef enum {
  64         MATCH_ITEM_PT,          /* Program header (PT_) */
  65         MATCH_ITEM_SHT          /* Section header (SHT_) */
  66 } match_item_t;
  67 
  68 /* match_opt_t is  used to note which match option was used */
  69 typedef enum {
  70         MATCH_OPT_NAME,         /* Record contains a name */
  71         MATCH_OPT_NDX,          /* Record contains a single index */
  72         MATCH_OPT_RANGE,        /* Record contains an index range */
  73         MATCH_OPT_TYPE,         /* Record contains a type (shdr or phdr) */
  74 } match_opt_t;
  75 
  76 typedef struct _match {
  77         struct _match   *next;          /* Pointer to next item in list */
  78         match_opt_t     opt_type;
  79         union {
  80                 const char      *name;  /* MATCH_OPT_NAME */
  81                 struct {                /* MATCH_OPT_NDX and MATCH_OPT_RANGE */
  82                         int     start;
  83                         int     end;    /* Only for MATCH_OPT_RANGE */
  84                 } ndx;
  85                 uint32_t        type;   /* MATCH_OPT_TYPE */
  86         } value;
  87 } match_rec_t;
  88 
  89 static struct {
  90         match_item_t    item_type;      /* Type of item being matched */
  91         match_rec_t     *list;          /* Records for (-I, -N, -T) options */
  92 } match_state;
  93 
  94 
  95 
  96 const char *
  97 _elfdump_msg(Msg mid)
  98 {
  99         return (gettext(MSG_ORIG(mid)));
 100 }
 101 
 102 /*
 103  * Determine whether a symbol name should be demangled.
 104  */
 105 const char *
 106 demangle(const char *name, uint_t flags)
 107 {
 108         if (flags & FLG_CTL_DEMANGLE)
 109                 return (Elf_demangle_name(name));
 110         else
 111                 return ((char *)name);
 112 }
 113 
 114 /*
 115  * Define our own standard error routine.
 116  */
 117 void
 118 failure(const char *file, const char *func)
 119 {
 120         (void) fprintf(stderr, MSG_INTL(MSG_ERR_FAILURE),
 121             file, func, elf_errmsg(elf_errno()));
 122 }
 123 
 124 /*
 125  * The full usage message
 126  */
 127 static void
 128 detail_usage()
 129 {
 130         (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL1));
 131         (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL2));
 132         (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL3));
 133         (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL4));
 134         (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL5));
 135         (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL6));
 136         (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL7));
 137         (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL8));
 138         (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL9));
 139         (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL10));
 140         (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL11));
 141         (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL12));
 142         (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL13));
 143         (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL14));
 144         (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL15));
 145         (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL16));
 146         (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL17));
 147         (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL18));
 148         (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL19));
 149         (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL20));
 150         (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL21));
 151         (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL22));
 152         (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL23));
 153         (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL24));
 154         (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL25));
 155         (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL26));
 156 }
 157 
 158 /*
 159  * Output a block of raw data as hex bytes. Each row is given
 160  * the index of the first byte in the row.
 161  *
 162  * entry:
 163  *      data - Pointer to first byte of data to be displayed
 164  *      n - # of bytes of data
 165  *      prefix - String to be output before each line. Useful
 166  *              for indenting output.
 167  *      bytes_per_col - # of space separated bytes to output
 168  *              in each column.
 169  *      col_per_row - # of columns to output per row
 170  *
 171  * exit:
 172  *      The formatted data has been sent to stdout. Each row of output
 173  *      shows (bytes_per_col * col_per_row) bytes of data.
 174  */
 175 void
 176 dump_hex_bytes(const void *data, size_t n, int indent,
 177         int bytes_per_col, int col_per_row)
 178 {
 179         const uchar_t *ldata = data;
 180         int     bytes_per_row = bytes_per_col * col_per_row;
 181         int     ndx, byte, word;
 182         char    string[128], *str = string;
 183         char    index[MAXNDXSIZE];
 184         int     index_width;
 185         int     sp_prefix = 0;
 186 
 187 
 188         /*
 189          * Determine the width to use for the index string. We follow
 190          * 8-byte tab rules, but don't use an actual \t character so
 191          * that the output can be arbitrarily shifted without odd
 192          * tab effects, and so that all the columns line up no matter
 193          * how many lines of output are produced.
 194          */
 195         ndx = n / bytes_per_row;
 196         (void) snprintf(index, sizeof (index),
 197             MSG_ORIG(MSG_FMT_INDEX2), EC_WORD(ndx));
 198         index_width = strlen(index);
 199         index_width = S_ROUND(index_width, 8);
 200 
 201         for (ndx = byte = word = 0; n > 0; n--, ldata++) {
 202                 while (sp_prefix-- > 0)
 203                         *str++ = ' ';
 204 
 205                 (void) snprintf(str, sizeof (string),
 206                     MSG_ORIG(MSG_HEXDUMP_TOK), (int)*ldata);
 207                 str += 2;
 208                 sp_prefix = 1;
 209 
 210                 if (++byte == bytes_per_col) {
 211                         sp_prefix += 2;
 212                         word++;
 213                         byte = 0;
 214                 }
 215                 if (word == col_per_row) {
 216                         *str = '\0';
 217                         (void) snprintf(index, sizeof (index),
 218                             MSG_ORIG(MSG_FMT_INDEX2), EC_WORD(ndx));
 219                         dbg_print(0, MSG_ORIG(MSG_HEXDUMP_ROW),
 220                             indent, MSG_ORIG(MSG_STR_EMPTY),
 221                             index_width, index, string);
 222                         sp_prefix = 0;
 223                         word = 0;
 224                         ndx += bytes_per_row;
 225                         str = string;
 226                 }
 227         }
 228         if (byte || word) {
 229                 *str = '\0';    /*  */
 230                 (void) snprintf(index, sizeof (index),
 231                     MSG_ORIG(MSG_FMT_INDEX2), EC_WORD(ndx));
 232                 dbg_print(0, MSG_ORIG(MSG_HEXDUMP_ROW), indent,
 233                     MSG_ORIG(MSG_STR_EMPTY), index_width, index, string);
 234         }
 235 }
 236 
 237 /*
 238  * Convert the ASCII representation of an index, or index range, into
 239  * binary form, and store it in rec:
 240  *
 241  *      index: An positive or 0 valued integer
 242  *      range: Two indexes, separated by a ':' character, denoting
 243  *              a range of allowed values. If the second value is omitted,
 244  *              any values equal to or greater than the first will match.
 245  *
 246  * exit:
 247  *      On success, *rec is filled in with a MATCH_OPT_NDX or MATCH_OPT_RANGE
 248  *      value, and this function returns (1). On failure, the contents
 249  *      of *rec are undefined, and (0) is returned.
 250  */
 251 int
 252 process_index_opt(const char *str, match_rec_t *rec)
 253 {
 254 #define SKIP_BLANK for (; *str && isspace(*str); str++)
 255 
 256         char    *endptr;
 257 
 258         rec->value.ndx.start = strtol(str, &endptr, 10);
 259         /* Value must use some of the input, and be 0 or positive */
 260         if ((str == endptr) || (rec->value.ndx.start < 0))
 261                 return (0);
 262         str = endptr;
 263 
 264         SKIP_BLANK;
 265         if (*str != ':') {
 266                 rec->opt_type = MATCH_OPT_NDX;
 267         } else {
 268                 str++;                                  /* Skip the ':' */
 269                 rec->opt_type = MATCH_OPT_RANGE;
 270                 SKIP_BLANK;
 271                 if (*str == '\0') {
 272                         rec->value.ndx.end = -1;     /* Indicates "to end" */
 273                 } else {
 274                         rec->value.ndx.end = strtol(str, &endptr, 10);
 275                         if ((str == endptr) || (rec->value.ndx.end < 0))
 276                                 return (0);
 277                         str = endptr;
 278                         SKIP_BLANK;
 279                 }
 280         }
 281 
 282         /* Syntax error if anything is left over */
 283         if (*str != '\0')
 284                 return (0);
 285 
 286         return (1);
 287 
 288 #undef  SKIP_BLANK
 289 }
 290 
 291 /*
 292  * Convert a string containing a specific type of ELF constant, or an ASCII
 293  * representation of a number, to an integer. Strings starting with '0'
 294  * are taken to be octal, those staring with '0x' are hex, and all
 295  * others are decimal.
 296  *
 297  * entry:
 298  *      str - String to be converted
 299  *      ctype - Constant type
 300  *      v - Address of variable to receive resulting value.
 301  *
 302  * exit:
 303  *      On success, returns True (1) and *v is set to the value.
 304  *      On failure, returns False (0) and *v is undefined.
 305  */
 306 typedef enum {
 307         ATOUI_PT,
 308         ATOUI_SHT,
 309         ATOUI_OSABI
 310 } atoui_type_t;
 311 
 312 static int
 313 atoui(const char *str, atoui_type_t type, uint32_t *v)
 314 {
 315         conv_strtol_uvalue_t    uvalue;
 316         char                    *endptr;
 317 
 318         if (conv_iter_strtol_init(str, &uvalue) != 0) {
 319                 switch (type) {
 320                 case ATOUI_PT:
 321                         if (conv_iter_phdr_type(CONV_OSABI_ALL, CONV_FMT_ALT_CF,
 322                             conv_iter_strtol, &uvalue) == CONV_ITER_DONE)
 323                                 break;
 324                         (void) conv_iter_phdr_type(CONV_OSABI_ALL,
 325                             CONV_FMT_ALT_NF, conv_iter_strtol, &uvalue);
 326                         break;
 327                 case ATOUI_SHT:
 328                         if (conv_iter_sec_type(CONV_OSABI_ALL, CONV_MACH_ALL,
 329                             CONV_FMT_ALT_CF, conv_iter_strtol, &uvalue) ==
 330                             CONV_ITER_DONE)
 331                                 break;
 332                         (void) conv_iter_sec_type(CONV_OSABI_ALL, CONV_MACH_ALL,
 333                             CONV_FMT_ALT_NF, conv_iter_strtol, &uvalue);
 334                         break;
 335                 case ATOUI_OSABI:
 336                         if (conv_iter_ehdr_osabi(CONV_FMT_ALT_CF,
 337                             conv_iter_strtol, &uvalue) == CONV_ITER_DONE)
 338                                 break;
 339                         (void) conv_iter_ehdr_osabi(CONV_FMT_ALT_NF,
 340                             conv_iter_strtol, &uvalue);
 341                         break;
 342                 }
 343                 if (uvalue.csl_found) {
 344                         *v = uvalue.csl_value;
 345                         return (1);
 346                 }
 347         }
 348 
 349         *v = strtoull(str, &endptr, 0);
 350 
 351         /* If the left over part contains anything but whitespace, fail */
 352         for (; *endptr; endptr++)
 353                 if (!isspace(*endptr))
 354                         return (0);
 355         return (1);
 356 }
 357 
 358 /*
 359  * Called after getopt() processing is finished if there is a non-empty
 360  * match list. Prepares the matching code for use.
 361  *
 362  * exit:
 363  *      Returns True (1) if no errors are encountered. Writes an
 364  *      error string to stderr and returns False (0) otherwise.
 365  */
 366 static int
 367 match_prepare(char *argv0, uint_t flags)
 368 {
 369         match_rec_t     *list;
 370         const char      *str;
 371         int             minus_p = (flags & FLG_SHOW_PHDR) != 0;
 372         atoui_type_t    atoui_type;
 373 
 374         /*
 375          * Flag ambiguous attempt to use match option with both -p and
 376          * and one or more section SHOW options. In this case, we
 377          * can't tell what type of item we're supposed to match against.
 378          */
 379         if (minus_p && (flags & FLG_MASK_SHOW_SHDR)) {
 380                 (void) fprintf(stderr, MSG_INTL(MSG_ERR_AMBIG_MATCH),
 381                     basename(argv0));
 382                 return (0);
 383         }
 384 
 385         /* Set the match type, based on the presence of the -p option */
 386         if (minus_p) {
 387                 match_state.item_type = MATCH_ITEM_PT;
 388                 atoui_type = ATOUI_PT;
 389         } else {
 390                 match_state.item_type = MATCH_ITEM_SHT;
 391                 atoui_type = ATOUI_SHT;
 392         }
 393 
 394         /*
 395          * Scan match list and perform any necessary fixups:
 396          *
 397          * MATCH_OPT_NAME: If -p is specified, convert MATCH_OPT_NAME (-N)
 398          *      requests into MATCH_OPT_TYPE (-T).
 399          *
 400          * MATCH_OPT_TYPE: Now that we know item type we are matching
 401          *      against, we can convert the string saved in the name
 402          *      field during getopt() processing into an integer and
 403          *      write it into the type field.
 404          */
 405         for (list = match_state.list; list; list = list->next) {
 406                 if ((list->opt_type == MATCH_OPT_NAME) && minus_p)
 407                         list->opt_type = MATCH_OPT_TYPE;
 408 
 409                 if (list->opt_type != MATCH_OPT_TYPE)
 410                         continue;
 411 
 412                 str = list->value.name;
 413                 if (atoui(str, atoui_type, &list->value.type) == 0) {
 414                         const char *fmt = minus_p ?
 415                             MSG_INTL(MSG_ERR_BAD_T_PT) :
 416                             MSG_INTL(MSG_ERR_BAD_T_SHT);
 417 
 418                         (void) fprintf(stderr, fmt, basename(argv0), str);
 419                         return (0);
 420                 }
 421         }
 422 
 423         return (1);
 424 }
 425 
 426 
 427 /*
 428  * Returns True (1) if the item with the given name or index should
 429  * be displayed, and False (0) if it should not be.
 430  *
 431  * entry:
 432  *      match_flags - Bitmask specifying matching options, as described
 433  *              in _elfdump.h.
 434  *      name - If MATCH_F_NAME flag is set, name of item under
 435  *              consideration. Otherwise ignored.
 436  *              should not be considered.
 437  *      ndx - If MATCH_F_NDX flag is set, index of item under consideration.
 438  *      type - If MATCH_F_TYPE is set, type of item under consideration.
 439  *              If MATCH_F_PHDR is set, this would be a program
 440  *              header type (PT_). Otherwise, a section header type (SHT_).
 441  *
 442  * exit:
 443  *      True will be returned if the given name/index matches those given
 444  *      by one of the (-I, -N -T) command line options, or if no such option
 445  *      was used in the command invocation and MATCH_F_STRICT is not
 446  *      set.
 447  */
 448 int
 449 match(match_flags_t match_flags, const char *name, uint_t ndx, uint_t type)
 450 {
 451         match_item_t item_type = (match_flags & MATCH_F_PHDR) ?
 452             MATCH_ITEM_PT  : MATCH_ITEM_SHT;
 453         match_rec_t *list;
 454 
 455         /*
 456          * If there is no match list, then we use the MATCH_F_STRICT
 457          * flag to decide what to return. In the strict case, we return
 458          * False (0), in the normal case, True (1).
 459          */
 460         if (match_state.list == NULL)
 461                 return ((match_flags & MATCH_F_STRICT) == 0);
 462 
 463         /*
 464          * If item being checked is not the current match type,
 465          * then allow it.
 466          */
 467         if (item_type != match_state.item_type)
 468                 return (1);
 469 
 470         /* Run through the match records and check for a hit */
 471         for (list = match_state.list; list; list = list->next) {
 472                 switch (list->opt_type) {
 473                 case MATCH_OPT_NAME:
 474                         if (((match_flags & MATCH_F_NAME) == 0) ||
 475                             (name == NULL))
 476                                 break;
 477                         if (strcmp(list->value.name, name) == 0)
 478                                 return (1);
 479                         break;
 480                 case MATCH_OPT_NDX:
 481                         if ((match_flags & MATCH_F_NDX) &&
 482                             (ndx == list->value.ndx.start))
 483                                 return (1);
 484                         break;
 485                 case MATCH_OPT_RANGE:
 486                         /*
 487                          * A range end value less than 0 means that any value
 488                          * above the start is acceptible.
 489                          */
 490                         if ((match_flags & MATCH_F_NDX) &&
 491                             (ndx >= list->value.ndx.start) &&
 492                             ((list->value.ndx.end < 0) ||
 493                             (ndx <= list->value.ndx.end)))
 494                                 return (1);
 495                         break;
 496 
 497                 case MATCH_OPT_TYPE:
 498                         if ((match_flags & MATCH_F_TYPE) &&
 499                             (type == list->value.type))
 500                                 return (1);
 501                         break;
 502                 }
 503         }
 504 
 505         /* Nothing matched */
 506         return (0);
 507 }
 508 
 509 /*
 510  * Add an entry to match_state.list for use by match(). This routine is for
 511  * use during getopt() processing. It should not be called once
 512  * match_prepare() has been called.
 513  *
 514  * Return True (1) for success. On failure, an error is written
 515  * to stderr, and False (0) is returned.
 516  */
 517 static int
 518 add_match_record(char *argv0, match_rec_t *data)
 519 {
 520         match_rec_t     *rec;
 521         match_rec_t     *list;
 522 
 523         if ((rec = malloc(sizeof (*rec))) == NULL) {
 524                 int err = errno;
 525                 (void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC),
 526                     basename(argv0), strerror(err));
 527                 return (0);
 528         }
 529 
 530         *rec = *data;
 531 
 532         /* Insert at end of match_state.list */
 533         if (match_state.list == NULL) {
 534                 match_state.list = rec;
 535         } else {
 536                 for (list = match_state.list; list->next != NULL;
 537                     list = list->next)
 538                         ;
 539                 list->next = rec;
 540         }
 541 
 542         rec->next = NULL;
 543         return (1);
 544 }
 545 
 546 static int
 547 decide(const char *file, int fd, Elf *elf, uint_t flags,
 548     const char *wname, int wfd, uchar_t osabi)
 549 {
 550         int r;
 551 
 552         if (gelf_getclass(elf) == ELFCLASS64)
 553                 r = regular64(file, fd, elf, flags, wname, wfd, osabi);
 554         else
 555                 r = regular32(file, fd, elf, flags, wname, wfd, osabi);
 556 
 557         return (r);
 558 }
 559 
 560 static int
 561 archive(const char *file, int fd, Elf *elf, uint_t flags,
 562     const char *wname, int wfd, uchar_t osabi)
 563 {
 564         Elf_Cmd         cmd = ELF_C_READ;
 565         Elf_Arhdr       *arhdr;
 566         Elf             *_elf = NULL;
 567         size_t          ptr;
 568         Elf_Arsym       *arsym = NULL;
 569 
 570         /*
 571          * Determine if the archive symbol table itself is required.
 572          */
 573         if ((flags & FLG_SHOW_SYMBOLS) &&
 574             match(MATCH_F_NAME, MSG_ORIG(MSG_ELF_ARSYM), 0, 0)) {
 575                 /*
 576                  * Get the archive symbol table.
 577                  */
 578                 if (((arsym = elf_getarsym(elf, &ptr)) == 0) && elf_errno()) {
 579                         /*
 580                          * The arsym could be 0 even though there was no error.
 581                          * Print the error message only when there was
 582                          * real error from elf_getarsym().
 583                          */
 584                         failure(file, MSG_ORIG(MSG_ELF_GETARSYM));
 585                         return (0);
 586                 }
 587         }
 588 
 589         /*
 590          * Print the archive symbol table only when the archive symbol
 591          * table exists and it was requested to print.
 592          */
 593         if (arsym) {
 594                 size_t          cnt;
 595                 char            index[MAXNDXSIZE];
 596                 size_t          offset = 0, _offset = 0;
 597                 const char      *fmt_arsym1, *fmt_arsym2;
 598 
 599                 /*
 600                  * Print out all the symbol entries. The format width used
 601                  * corresponds to whether the archive symbol table is 32
 602                  * or 64-bit. We see them via Elf_Arhdr as size_t values
 603                  * in either case with no information loss (see the comments
 604                  * in libelf/getarsym.c) so this is done simply to improve
 605                  * the user presentation.
 606                  */
 607                 if (_elf_getarsymwordsize(elf) == 8) {
 608                         dbg_print(0, MSG_INTL(MSG_ARCHIVE_SYMTAB_64));
 609                         dbg_print(0, MSG_INTL(MSG_ARCHIVE_FIELDS_64));
 610 
 611                         fmt_arsym1 = MSG_ORIG(MSG_FMT_ARSYM1_64);
 612                         fmt_arsym2 = MSG_ORIG(MSG_FMT_ARSYM2_64);
 613                 } else {
 614                         dbg_print(0, MSG_INTL(MSG_ARCHIVE_SYMTAB_32));
 615                         dbg_print(0, MSG_INTL(MSG_ARCHIVE_FIELDS_32));
 616 
 617                         fmt_arsym1 = MSG_ORIG(MSG_FMT_ARSYM1_32);
 618                         fmt_arsym2 = MSG_ORIG(MSG_FMT_ARSYM2_32);
 619                 }
 620 
 621                 for (cnt = 0; cnt < ptr; cnt++, arsym++) {
 622                         /*
 623                          * For each object obtain an elf descriptor so that we
 624                          * can establish the members name.  Note, we have had
 625                          * archives where the archive header has not been
 626                          * obtainable so be lenient with errors.
 627                          */
 628                         if ((offset == 0) || ((arsym->as_off != 0) &&
 629                             (arsym->as_off != _offset))) {
 630 
 631                                 if (_elf)
 632                                         (void) elf_end(_elf);
 633 
 634                                 if (elf_rand(elf, arsym->as_off) !=
 635                                     arsym->as_off) {
 636                                         failure(file, MSG_ORIG(MSG_ELF_RAND));
 637                                         arhdr = NULL;
 638                                 } else if ((_elf = elf_begin(fd,
 639                                     ELF_C_READ, elf)) == 0) {
 640                                         failure(file, MSG_ORIG(MSG_ELF_BEGIN));
 641                                         arhdr = NULL;
 642                                 } else if ((arhdr = elf_getarhdr(_elf)) == 0) {
 643                                         failure(file,
 644                                             MSG_ORIG(MSG_ELF_GETARHDR));
 645                                         arhdr = NULL;
 646                                 }
 647 
 648                                 _offset = arsym->as_off;
 649                                 if (offset == 0)
 650                                         offset = _offset;
 651                         }
 652 
 653                         (void) snprintf(index, MAXNDXSIZE,
 654                             MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(cnt));
 655                         if (arsym->as_off)
 656                                 dbg_print(0, fmt_arsym1, index,
 657                                     EC_XWORD(arsym->as_off),
 658                                     arhdr ? arhdr->ar_name :
 659                                     MSG_INTL(MSG_STR_UNKNOWN), (arsym->as_name ?
 660                                     demangle(arsym->as_name, flags) :
 661                                     MSG_INTL(MSG_STR_NULL)));
 662                         else
 663                                 dbg_print(0, fmt_arsym2, index,
 664                                     EC_XWORD(arsym->as_off));
 665                 }
 666 
 667                 if (_elf)
 668                         (void) elf_end(_elf);
 669 
 670                 /*
 671                  * If we only need the archive symbol table return.
 672                  */
 673                 if ((flags & FLG_SHOW_SYMBOLS) &&
 674                     match(MATCH_F_STRICT | MATCH_F_NAME,
 675                     MSG_ORIG(MSG_ELF_ARSYM), -1, -1))
 676                         return (0);
 677 
 678                 /*
 679                  * Reset elf descriptor in preparation for processing each
 680                  * member.
 681                  */
 682                 if (offset)
 683                         (void) elf_rand(elf, offset);
 684         }
 685 
 686         /*
 687          * Process each object within the archive.
 688          */
 689         while ((_elf = elf_begin(fd, cmd, elf)) != NULL) {
 690                 char    name[MAXPATHLEN];
 691 
 692                 if ((arhdr = elf_getarhdr(_elf)) == NULL) {
 693                         failure(file, MSG_ORIG(MSG_ELF_GETARHDR));
 694                         return (0);
 695                 }
 696                 if (*arhdr->ar_name != '/') {
 697                         (void) snprintf(name, MAXPATHLEN,
 698                             MSG_ORIG(MSG_FMT_ARNAME), file, arhdr->ar_name);
 699                         dbg_print(0, MSG_ORIG(MSG_FMT_NLSTR), name);
 700 
 701                         switch (elf_kind(_elf)) {
 702                         case ELF_K_AR:
 703                                 if (archive(name, fd, _elf, flags,
 704                                     wname, wfd, osabi) == 1)
 705                                         return (1);
 706                                 break;
 707                         case ELF_K_ELF:
 708                                 if (decide(name, fd, _elf, flags,
 709                                     wname, wfd, osabi) == 1)
 710                                         return (1);
 711                                 break;
 712                         default:
 713                                 (void) fprintf(stderr,
 714                                     MSG_INTL(MSG_ERR_BADFILE), name);
 715                                 break;
 716                         }
 717                 }
 718 
 719                 cmd = elf_next(_elf);
 720                 (void) elf_end(_elf);
 721         }
 722 
 723         return (0);
 724 }
 725 
 726 int
 727 main(int argc, char **argv, char **envp)
 728 {
 729         Elf             *elf;
 730         int             var, fd, wfd = 0;
 731         char            *wname = NULL;
 732         uint_t          flags = 0;
 733         match_rec_t     match_data;
 734         int             ret;
 735         uchar_t         osabi;
 736 
 737         /*
 738          * If we're on a 64-bit kernel, try to exec a full 64-bit version of
 739          * the binary.  If successful, conv_check_native() won't return.
 740          */
 741         (void) conv_check_native(argv, envp);
 742 
 743         /*
 744          * Establish locale.
 745          */
 746         (void) setlocale(LC_MESSAGES, MSG_ORIG(MSG_STR_EMPTY));
 747         (void) textdomain(MSG_ORIG(MSG_SUNW_OST_SGS));
 748 
 749         (void) setvbuf(stdout, NULL, _IOLBF, 0);
 750         (void) setvbuf(stderr, NULL, _IOLBF, 0);
 751 
 752         opterr = 0;
 753         while ((var = getopt(argc, argv, MSG_ORIG(MSG_STR_OPTIONS))) != EOF) {
 754                 switch (var) {
 755                 case 'C':
 756                         flags |= FLG_CTL_DEMANGLE;
 757                         break;
 758                 case 'c':
 759                         flags |= FLG_SHOW_SHDR;
 760                         break;
 761                 case 'd':
 762                         flags |= FLG_SHOW_DYNAMIC;
 763                         break;
 764                 case 'e':
 765                         flags |= FLG_SHOW_EHDR;
 766                         break;
 767                 case 'G':
 768                         flags |= FLG_SHOW_GOT;
 769                         break;
 770                 case 'g':
 771                         flags |= FLG_SHOW_GROUP;
 772                         break;
 773                 case 'H':
 774                         flags |= FLG_SHOW_CAP;
 775                         break;
 776                 case 'h':
 777                         flags |= FLG_SHOW_HASH;
 778                         break;
 779                 case 'I':
 780                         if (!process_index_opt(optarg, &match_data))
 781                                 goto usage_brief;
 782                         if (!add_match_record(argv[0], &match_data))
 783                                 return (1);
 784                         flags |= FLG_CTL_MATCH;
 785                         break;
 786                 case 'i':
 787                         flags |= FLG_SHOW_INTERP;
 788                         break;
 789                 case 'k':
 790                         flags |= FLG_CALC_CHECKSUM;
 791                         break;
 792                 case 'l':
 793                         flags |= FLG_CTL_LONGNAME;
 794                         break;
 795                 case 'm':
 796                         flags |= FLG_SHOW_MOVE;
 797                         break;
 798                 case 'N':
 799                         match_data.opt_type = MATCH_OPT_NAME;
 800                         match_data.value.name = optarg;
 801                         if (!add_match_record(argv[0], &match_data))
 802                                 return (1);
 803                         flags |= FLG_CTL_MATCH;
 804                         break;
 805                 case 'n':
 806                         flags |= FLG_SHOW_NOTE;
 807                         break;
 808                 case 'O':
 809                         {
 810                                 uint32_t val;
 811 
 812                                 /*
 813                                  * osabi is a uchar_t in the ELF header.
 814                                  * Don't accept any value that exceeds
 815                                  * that range.
 816                                  */
 817                                 if ((atoui(optarg, ATOUI_OSABI, &val) == 0) ||
 818                                     (val > 255)) {
 819                                         (void) fprintf(stderr,
 820                                             MSG_INTL(MSG_ERR_BAD_T_OSABI),
 821                                             basename(argv[0]), optarg);
 822                                         return (1);
 823                                 }
 824                                 osabi = val;
 825                         }
 826                         flags |= FLG_CTL_OSABI;
 827                         break;
 828                 case 'P':
 829                         flags |= FLG_CTL_FAKESHDR;
 830                         break;
 831                 case 'p':
 832                         flags |= FLG_SHOW_PHDR;
 833                         break;
 834                 case 'r':
 835                         flags |= FLG_SHOW_RELOC;
 836                         break;
 837                 case 'S':
 838                         flags |= FLG_SHOW_SORT;
 839                         break;
 840                 case 's':
 841                         flags |= FLG_SHOW_SYMBOLS;
 842                         break;
 843                 case 'T':
 844                         /*
 845                          * We can't evaluate the value yet, because
 846                          * we need to know if -p is used or not in
 847                          * order to tell if we're seeing section header
 848                          * or program header types. So, we save the
 849                          * string in the name field, and then convert
 850                          * it to a type integer in a following pass.
 851                          */
 852                         match_data.opt_type = MATCH_OPT_TYPE;
 853                         match_data.value.name = optarg;
 854                         if (!add_match_record(argv[0], &match_data))
 855                                 return (1);
 856                         flags |= FLG_CTL_MATCH;
 857                         break;
 858                 case 'u':
 859                         flags |= FLG_SHOW_UNWIND;
 860                         break;
 861                 case 'v':
 862                         flags |= FLG_SHOW_VERSIONS;
 863                         break;
 864                 case 'w':
 865                         wname = optarg;
 866                         break;
 867                 case 'y':
 868                         flags |= FLG_SHOW_SYMINFO;
 869                         break;
 870                 case '?':
 871                         (void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF),
 872                             basename(argv[0]));
 873                         detail_usage();
 874                         return (1);
 875                 default:
 876                         break;
 877                 }
 878         }
 879 
 880         /* -p and -w are mutually exclusive. -w only works with sections */
 881         if (((flags & FLG_SHOW_PHDR) != 0) && (wname != NULL))
 882                 goto usage_brief;
 883 
 884         /* If a match argument is present, prepare the match state */
 885         if ((match_state.list != NULL) && (match_prepare(argv[0], flags) == 0))
 886                 return (1);
 887 
 888         /*
 889          * Decide what to do if no options specifying something to
 890          * show or do are present.
 891          *
 892          * If there is no -w and no match options, then we will set all
 893          * the show flags, causing a full display of everything in the
 894          * file that we know how to handle.
 895          *
 896          * Otherwise, if there is no match list, we generate a usage
 897          * error and quit.
 898          *
 899          * In the case where there is a match list, we go ahead and call
 900          * regular() anyway, leaving it to decide what to do. If -w is
 901          * present, regular() will use the match list to handle it.
 902          * In addition, in the absence of explicit show/calc flags, regular()
 903          * will compare the section headers to the match list and use
 904          * that to generate the FLG_ bits that will display the information
 905          * specified by the match list.
 906          */
 907         if ((flags & ~FLG_MASK_CTL) == 0) {
 908                 if (!wname && (match_state.list == NULL))
 909                         flags |= FLG_MASK_SHOW;
 910                 else if (match_state.list == NULL)
 911                         goto usage_brief;
 912         }
 913 
 914         /* There needs to be at least 1 filename left following the options */
 915         if ((var = argc - optind) == 0)
 916                 goto usage_brief;
 917 
 918         /*
 919          * If the -l/-C option is specified, set up the liblddbg.so.
 920          */
 921         if (flags & FLG_CTL_LONGNAME)
 922                 dbg_desc->d_extra |= DBG_E_LONG;
 923         if (flags & FLG_CTL_DEMANGLE)
 924                 dbg_desc->d_extra |= DBG_E_DEMANGLE;
 925 
 926         /*
 927          * If the -w option has indicated an output file open it.  It's
 928          * arguable whether this option has much use when multiple files are
 929          * being processed.
 930          *
 931          * If wname is non-NULL, we know that -p was not specified, due
 932          * to the test above.
 933          */
 934         if (wname) {
 935                 if ((wfd = open(wname, (O_RDWR | O_CREAT | O_TRUNC),
 936                     0666)) < 0) {
 937                         int err = errno;
 938                         (void) fprintf(stderr, MSG_INTL(MSG_ERR_OPEN),
 939                             wname, strerror(err));
 940                         return (1);
 941                 }
 942         }
 943 
 944         /*
 945          * Open the input file, initialize the elf interface, and
 946          * process it.
 947          */
 948         ret = 0;
 949         for (; (optind < argc) && (ret == 0); optind++) {
 950                 const char      *file = argv[optind];
 951 
 952                 if ((fd = open(argv[optind], O_RDONLY)) == -1) {
 953                         int err = errno;
 954                         (void) fprintf(stderr, MSG_INTL(MSG_ERR_OPEN),
 955                             file, strerror(err));
 956                         continue;
 957                 }
 958                 (void) elf_version(EV_CURRENT);
 959                 if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
 960                         failure(file, MSG_ORIG(MSG_ELF_BEGIN));
 961                         (void) close(fd);
 962                         continue;
 963                 }
 964 
 965                 if (var > 1)
 966                         dbg_print(0, MSG_ORIG(MSG_FMT_NLSTRNL), file);
 967 
 968                 switch (elf_kind(elf)) {
 969                 case ELF_K_AR:
 970                         ret = archive(file, fd, elf, flags, wname, wfd, osabi);
 971                         break;
 972                 case ELF_K_ELF:
 973                         ret = decide(file, fd, elf, flags, wname, wfd, osabi);
 974                         break;
 975                 default:
 976                         (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADFILE), file);
 977                         ret = 1;
 978                         break;
 979                 }
 980 
 981                 (void) close(fd);
 982                 (void) elf_end(elf);
 983         }
 984 
 985         if (wfd)
 986                 (void) close(wfd);
 987         return (ret);
 988 
 989 usage_brief:
 990         /* Control comes here for a simple usage message and exit */
 991         (void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF),
 992             basename(argv[0]));
 993         return (1);
 994 
 995 }