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 }