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