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 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * Dump an elf file. 30 */ 31 #include <sys/param.h> 32 #include <fcntl.h> 33 #include <stdio.h> 34 #include <stdlib.h> 35 #include <ctype.h> 36 #include <libelf.h> 37 #include <link.h> 38 #include <stdarg.h> 39 #include <unistd.h> 40 #include <libgen.h> 41 #include <libintl.h> 42 #include <locale.h> 43 #include <errno.h> 44 #include <strings.h> 45 #include <debug.h> 46 #include <conv.h> 47 #include <msg.h> 48 #include <_elfdump.h> 49 #include <sys/elf_SPARC.h> 50 #include <sys/elf_amd64.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 /* Map names to their integer value */ 99 typedef struct { 100 const char *sym_name; 101 uint32_t sym_value; 102 } atoui_sym_t; 103 104 /* 105 * ELF section types. 106 */ 107 static atoui_sym_t sym_sht[] = { 108 { MSG_ORIG(MSG_SHT_NULL), SHT_NULL }, 109 { MSG_ORIG(MSG_SHT_NULL_ALT1), SHT_NULL }, 110 111 { MSG_ORIG(MSG_SHT_PROGBITS), SHT_PROGBITS }, 112 { MSG_ORIG(MSG_SHT_PROGBITS_ALT1), SHT_PROGBITS }, 113 114 { MSG_ORIG(MSG_SHT_SYMTAB), SHT_SYMTAB }, 115 { MSG_ORIG(MSG_SHT_SYMTAB_ALT1), SHT_SYMTAB }, 116 117 { MSG_ORIG(MSG_SHT_STRTAB), SHT_STRTAB }, 118 { MSG_ORIG(MSG_SHT_STRTAB_ALT1), SHT_STRTAB }, 119 120 { MSG_ORIG(MSG_SHT_RELA), SHT_RELA }, 121 { MSG_ORIG(MSG_SHT_RELA_ALT1), SHT_RELA }, 122 123 { MSG_ORIG(MSG_SHT_HASH), SHT_HASH }, 124 { MSG_ORIG(MSG_SHT_HASH_ALT1), SHT_HASH }, 125 126 { MSG_ORIG(MSG_SHT_DYNAMIC), SHT_DYNAMIC }, 127 { MSG_ORIG(MSG_SHT_DYNAMIC_ALT1), SHT_DYNAMIC }, 128 129 { MSG_ORIG(MSG_SHT_NOTE), SHT_NOTE }, 130 { MSG_ORIG(MSG_SHT_NOTE_ALT1), SHT_NOTE }, 131 132 { MSG_ORIG(MSG_SHT_NOBITS), SHT_NOBITS }, 133 { MSG_ORIG(MSG_SHT_NOBITS_ALT1), SHT_NOBITS }, 134 135 { MSG_ORIG(MSG_SHT_REL), SHT_REL }, 136 { MSG_ORIG(MSG_SHT_REL_ALT1), SHT_REL }, 137 138 { MSG_ORIG(MSG_SHT_SHLIB), SHT_SHLIB }, 139 { MSG_ORIG(MSG_SHT_SHLIB_ALT1), SHT_SHLIB }, 140 141 { MSG_ORIG(MSG_SHT_DYNSYM), SHT_DYNSYM }, 142 { MSG_ORIG(MSG_SHT_DYNSYM_ALT1), SHT_DYNSYM }, 143 144 { MSG_ORIG(MSG_SHT_INIT_ARRAY), SHT_INIT_ARRAY }, 145 { MSG_ORIG(MSG_SHT_INIT_ARRAY_ALT1), SHT_INIT_ARRAY }, 146 147 { MSG_ORIG(MSG_SHT_FINI_ARRAY), SHT_FINI_ARRAY }, 148 { MSG_ORIG(MSG_SHT_FINI_ARRAY_ALT1), SHT_FINI_ARRAY }, 149 150 { MSG_ORIG(MSG_SHT_PREINIT_ARRAY), SHT_PREINIT_ARRAY }, 151 { MSG_ORIG(MSG_SHT_PREINIT_ARRAY_ALT1), SHT_PREINIT_ARRAY }, 152 153 { MSG_ORIG(MSG_SHT_GROUP), SHT_GROUP }, 154 { MSG_ORIG(MSG_SHT_GROUP_ALT1), SHT_GROUP }, 155 156 { MSG_ORIG(MSG_SHT_SYMTAB_SHNDX), SHT_SYMTAB_SHNDX }, 157 { MSG_ORIG(MSG_SHT_SYMTAB_SHNDX_ALT1), SHT_SYMTAB_SHNDX }, 158 159 { MSG_ORIG(MSG_SHT_SUNW_SYMSORT), SHT_SUNW_symsort }, 160 { MSG_ORIG(MSG_SHT_SUNW_SYMSORT_ALT1), SHT_SUNW_symsort }, 161 162 { MSG_ORIG(MSG_SHT_SUNW_TLSSORT), SHT_SUNW_tlssort }, 163 { MSG_ORIG(MSG_SHT_SUNW_TLSSORT_ALT1), SHT_SUNW_tlssort }, 164 165 { MSG_ORIG(MSG_SHT_SUNW_LDYNSYM), SHT_SUNW_LDYNSYM }, 166 { MSG_ORIG(MSG_SHT_SUNW_LDYNSYM_ALT1), SHT_SUNW_LDYNSYM }, 167 168 { MSG_ORIG(MSG_SHT_SUNW_DOF), SHT_SUNW_dof }, 169 { MSG_ORIG(MSG_SHT_SUNW_DOF_ALT1), SHT_SUNW_dof }, 170 171 { MSG_ORIG(MSG_SHT_SUNW_CAP), SHT_SUNW_cap }, 172 { MSG_ORIG(MSG_SHT_SUNW_CAP_ALT1), SHT_SUNW_cap }, 173 174 { MSG_ORIG(MSG_SHT_SUNW_SIGNATURE), SHT_SUNW_SIGNATURE }, 175 { MSG_ORIG(MSG_SHT_SUNW_SIGNATURE_ALT1), SHT_SUNW_SIGNATURE }, 176 177 { MSG_ORIG(MSG_SHT_SUNW_ANNOTATE), SHT_SUNW_ANNOTATE }, 178 { MSG_ORIG(MSG_SHT_SUNW_ANNOTATE_ALT1), SHT_SUNW_ANNOTATE }, 179 180 { MSG_ORIG(MSG_SHT_SUNW_DEBUGSTR), SHT_SUNW_DEBUGSTR }, 181 { MSG_ORIG(MSG_SHT_SUNW_DEBUGSTR_ALT1), SHT_SUNW_DEBUGSTR }, 182 183 { MSG_ORIG(MSG_SHT_SUNW_DEBUG), SHT_SUNW_DEBUG }, 184 { MSG_ORIG(MSG_SHT_SUNW_DEBUG_ALT1), SHT_SUNW_DEBUG }, 185 186 { MSG_ORIG(MSG_SHT_SUNW_MOVE), SHT_SUNW_move }, 187 { MSG_ORIG(MSG_SHT_SUNW_MOVE_ALT1), SHT_SUNW_move }, 188 189 { MSG_ORIG(MSG_SHT_SUNW_COMDAT), SHT_SUNW_COMDAT }, 190 { MSG_ORIG(MSG_SHT_SUNW_COMDAT_ALT1), SHT_SUNW_COMDAT }, 191 192 { MSG_ORIG(MSG_SHT_SUNW_SYMINFO), SHT_SUNW_syminfo }, 193 { MSG_ORIG(MSG_SHT_SUNW_SYMINFO_ALT1), SHT_SUNW_syminfo }, 194 195 { MSG_ORIG(MSG_SHT_SUNW_VERDEF), SHT_SUNW_verdef }, 196 { MSG_ORIG(MSG_SHT_SUNW_VERDEF_ALT1), SHT_SUNW_verdef }, 197 198 { MSG_ORIG(MSG_SHT_GNU_VERDEF), SHT_GNU_verdef }, 199 { MSG_ORIG(MSG_SHT_GNU_VERDEF_ALT1), SHT_GNU_verdef }, 200 201 { MSG_ORIG(MSG_SHT_SUNW_VERNEED), SHT_SUNW_verneed }, 202 { MSG_ORIG(MSG_SHT_SUNW_VERNEED_ALT1), SHT_SUNW_verneed }, 203 204 { MSG_ORIG(MSG_SHT_GNU_VERNEED), SHT_GNU_verneed }, 205 { MSG_ORIG(MSG_SHT_GNU_VERNEED_ALT1), SHT_GNU_verneed }, 206 207 { MSG_ORIG(MSG_SHT_SUNW_VERSYM), SHT_SUNW_versym }, 208 { MSG_ORIG(MSG_SHT_SUNW_VERSYM_ALT1), SHT_SUNW_versym }, 209 210 { MSG_ORIG(MSG_SHT_GNU_VERSYM), SHT_GNU_versym }, 211 { MSG_ORIG(MSG_SHT_GNU_VERSYM_ALT1), SHT_GNU_versym }, 212 213 { MSG_ORIG(MSG_SHT_SPARC_GOTDATA), SHT_SPARC_GOTDATA }, 214 { MSG_ORIG(MSG_SHT_SPARC_GOTDATA_ALT1), SHT_SPARC_GOTDATA }, 215 216 { MSG_ORIG(MSG_SHT_AMD64_UNWIND), SHT_AMD64_UNWIND }, 217 { MSG_ORIG(MSG_SHT_AMD64_UNWIND_ALT1), SHT_AMD64_UNWIND }, 218 219 { NULL } 220 }; 221 222 /* 223 * Program header PT_* type values 224 */ 225 static atoui_sym_t sym_pt[] = { 226 { MSG_ORIG(MSG_PT_NULL), PT_NULL }, 227 { MSG_ORIG(MSG_PT_NULL_ALT1), PT_NULL }, 228 229 { MSG_ORIG(MSG_PT_LOAD), PT_LOAD }, 230 { MSG_ORIG(MSG_PT_LOAD_ALT1), PT_LOAD }, 231 232 { MSG_ORIG(MSG_PT_DYNAMIC), PT_DYNAMIC }, 233 { MSG_ORIG(MSG_PT_DYNAMIC_ALT1), PT_DYNAMIC }, 234 235 { MSG_ORIG(MSG_PT_INTERP), PT_INTERP }, 236 { MSG_ORIG(MSG_PT_INTERP_ALT1), PT_INTERP }, 237 238 { MSG_ORIG(MSG_PT_NOTE), PT_NOTE }, 239 { MSG_ORIG(MSG_PT_NOTE_ALT1), PT_NOTE }, 240 241 { MSG_ORIG(MSG_PT_SHLIB), PT_SHLIB }, 242 { MSG_ORIG(MSG_PT_SHLIB_ALT1), PT_SHLIB }, 243 244 { MSG_ORIG(MSG_PT_PHDR), PT_PHDR }, 245 { MSG_ORIG(MSG_PT_PHDR_ALT1), PT_PHDR }, 246 247 { MSG_ORIG(MSG_PT_TLS), PT_TLS }, 248 { MSG_ORIG(MSG_PT_TLS_ALT1), PT_TLS }, 249 250 { MSG_ORIG(MSG_PT_SUNW_UNWIND), PT_SUNW_UNWIND }, 251 { MSG_ORIG(MSG_PT_SUNW_UNWIND_ALT1), PT_SUNW_UNWIND }, 252 253 { MSG_ORIG(MSG_PT_SUNWBSS), PT_SUNWBSS }, 254 { MSG_ORIG(MSG_PT_SUNWBSS_ALT1), PT_SUNWBSS }, 255 256 { MSG_ORIG(MSG_PT_SUNWSTACK), PT_SUNWSTACK }, 257 { MSG_ORIG(MSG_PT_SUNWSTACK_ALT1), PT_SUNWSTACK }, 258 259 { MSG_ORIG(MSG_PT_SUNWDTRACE), PT_SUNWDTRACE }, 260 { MSG_ORIG(MSG_PT_SUNWDTRACE_ALT1), PT_SUNWDTRACE }, 261 262 { MSG_ORIG(MSG_PT_SUNWCAP), PT_SUNWCAP }, 263 { MSG_ORIG(MSG_PT_SUNWCAP_ALT1), PT_SUNWCAP }, 264 265 { NULL } 266 }; 267 268 269 270 271 272 const char * 273 _elfdump_msg(Msg mid) 274 { 275 return (gettext(MSG_ORIG(mid))); 276 } 277 278 /* 279 * Determine whether a symbol name should be demangled. 280 */ 281 const char * 282 demangle(const char *name, uint_t flags) 283 { 284 if (flags & FLG_CTL_DEMANGLE) 285 return (Elf_demangle_name(name)); 286 else 287 return ((char *)name); 288 } 289 290 /* 291 * Define our own standard error routine. 292 */ 293 void 294 failure(const char *file, const char *func) 295 { 296 (void) fprintf(stderr, MSG_INTL(MSG_ERR_FAILURE), 297 file, func, elf_errmsg(elf_errno())); 298 } 299 300 /* 301 * The full usage message 302 */ 303 static void 304 detail_usage() 305 { 306 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL1)); 307 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL2)); 308 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL3)); 309 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL4)); 310 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL5)); 311 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL6)); 312 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL7)); 313 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL8)); 314 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL9)); 315 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL10)); 316 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL11)); 317 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL12)); 318 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL13)); 319 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL14)); 320 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL15)); 321 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL16)); 322 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL17)); 323 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL18)); 324 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL19)); 325 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL20)); 326 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL21)); 327 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL22)); 328 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL23)); 329 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL24)); 330 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL25)); 331 } 332 333 /* 334 * Output a block of raw data as hex bytes. Each row is given 335 * the index of the first byte in the row. 336 * 337 * entry: 338 * data - Pointer to first byte of data to be displayed 339 * n - # of bytes of data 340 * prefix - String to be output before each line. Useful 341 * for indenting output. 342 * bytes_per_col - # of space separated bytes to output 343 * in each column. 344 * col_per_row - # of columns to output per row 345 * 346 * exit: 347 * The formatted data has been sent to stdout. Each row of output 348 * shows (bytes_per_col * col_per_row) bytes of data. 349 */ 350 void 351 dump_hex_bytes(const char *data, size_t n, int indent, 352 int bytes_per_col, int col_per_row) 353 { 354 int bytes_per_row = bytes_per_col * col_per_row; 355 int ndx, byte, word; 356 char string[128], *str = string; 357 char index[MAXNDXSIZE]; 358 int index_width; 359 int sp_prefix = 0; 360 361 362 /* 363 * Determine the width to use for the index string. We follow 364 * 8-byte tab rules, but don't use an actual \t character so 365 * that the output can be arbitrarily shifted without odd 366 * tab effects, and so that all the columns line up no matter 367 * how many lines of output are produced. 368 */ 369 ndx = n / bytes_per_row; 370 (void) snprintf(index, sizeof (index), 371 MSG_ORIG(MSG_FMT_INDEX2), EC_WORD(ndx)); 372 index_width = strlen(index); 373 index_width = S_ROUND(index_width, 8); 374 375 for (ndx = byte = word = 0; n > 0; n--, data++) { 376 while (sp_prefix-- > 0) 377 *str++ = ' '; 378 379 (void) snprintf(str, sizeof (string), 380 MSG_ORIG(MSG_HEXDUMP_TOK), (int)*data); 381 str += 2; 382 sp_prefix = 1; 383 384 if (++byte == bytes_per_col) { 385 sp_prefix += 2; 386 word++; 387 byte = 0; 388 } 389 if (word == col_per_row) { 390 *str = '\0'; 391 (void) snprintf(index, sizeof (index), 392 MSG_ORIG(MSG_FMT_INDEX2), EC_WORD(ndx)); 393 dbg_print(0, MSG_ORIG(MSG_HEXDUMP_ROW), 394 indent, MSG_ORIG(MSG_STR_EMPTY), 395 index_width, index, string); 396 sp_prefix = 0; 397 word = 0; 398 ndx += bytes_per_row; 399 str = string; 400 } 401 } 402 if (byte || word) { 403 *str = '\0'; /* */ 404 (void) snprintf(index, sizeof (index), 405 MSG_ORIG(MSG_FMT_INDEX2), EC_WORD(ndx)); 406 dbg_print(0, MSG_ORIG(MSG_HEXDUMP_ROW), indent, 407 MSG_ORIG(MSG_STR_EMPTY), index_width, index, string); 408 } 409 } 410 411 /* 412 * Convert the ASCII representation of an index, or index range, into 413 * binary form, and store it in rec: 414 * 415 * index: An positive or 0 valued integer 416 * range: Two indexes, separated by a ':' character, denoting 417 * a range of allowed values. If the second value is omitted, 418 * any values equal to or greater than the first will match. 419 * 420 * exit: 421 * On success, *rec is filled in with a MATCH_OPT_NDX or MATCH_OPT_RANGE 422 * value, and this function returns (1). On failure, the contents 423 * of *rec are undefined, and (0) is returned. 424 */ 425 int 426 process_index_opt(const char *str, match_rec_t *rec) 427 { 428 #define SKIP_BLANK for (; *str && isspace(*str); str++) 429 430 char *endptr; 431 432 rec->value.ndx.start = strtol(str, &endptr, 10); 433 /* Value must use some of the input, and be 0 or positive */ 434 if ((str == endptr) || (rec->value.ndx.start < 0)) 435 return (0); 436 str = endptr; 437 438 SKIP_BLANK; 439 if (*str != ':') { 440 rec->opt_type = MATCH_OPT_NDX; 441 } else { 442 str++; /* Skip the ':' */ 443 rec->opt_type = MATCH_OPT_RANGE; 444 SKIP_BLANK; 445 if (*str == '\0') { 446 rec->value.ndx.end = -1; /* Indicates "to end" */ 447 } else { 448 rec->value.ndx.end = strtol(str, &endptr, 10); 449 if ((str == endptr) || (rec->value.ndx.end < 0)) 450 return (0); 451 str = endptr; 452 SKIP_BLANK; 453 } 454 } 455 456 /* Syntax error if anything is left over */ 457 if (*str != '\0') 458 return (0); 459 460 return (1); 461 462 #undef SKIP_BLANK 463 } 464 465 /* 466 * Process the symbolic name to value mappings passed to the 467 * atoui() function. 468 * 469 * entry: 470 * sym - NULL terminated array of name->value mappings. 471 * value - Address of variable to receive corresponding value. 472 * 473 * exit: 474 * If a mapping is found, *value is set to it, and True is returned. 475 * Otherwise False is returned. 476 */ 477 static int 478 atoui_sym_process(const char *str, const atoui_sym_t *sym, uint32_t *value) 479 { 480 size_t cmp_len; 481 const char *tail; 482 483 while (isspace(*str)) 484 str++; 485 486 tail = str + strlen(str); 487 while ((tail > str) && isspace(*(tail - 1))) 488 tail--; 489 490 cmp_len = tail - str; 491 492 for (; sym->sym_name != NULL; sym++) { 493 if ((strlen(sym->sym_name) == cmp_len) && 494 (strncasecmp(sym->sym_name, str, cmp_len) == 0)) { 495 *value = sym->sym_value; 496 return (1); 497 } 498 } 499 500 /* No symbolic mapping was found */ 501 return (0); 502 } 503 504 505 /* 506 * Convert a string to a numeric value. Strings starting with '0' 507 * are taken to be octal, those staring with '0x' are hex, and all 508 * others are decimal. 509 * 510 * entry: 511 * str - String to be converted 512 * sym - NULL, or NULL terminated array of name/value pairs. 513 * v - Address of variable to receive resulting value. 514 * 515 * exit: 516 * On success, returns True (1) and *v is set to the value. 517 * On failure, returns False (0) and *v is undefined. 518 */ 519 static int 520 atoui(const char *str, const atoui_sym_t *sym, uint32_t *v) 521 { 522 char *endptr; 523 524 if (sym && atoui_sym_process(str, sym, v)) 525 return (1); 526 527 *v = strtoull(str, &endptr, 0); 528 529 /* If the left over part contains anything but whitespace, fail */ 530 for (; *endptr; endptr++) 531 if (!isspace(*endptr)) 532 return (0); 533 return (1); 534 } 535 536 /* 537 * Called after getopt() processing is finished if there is a non-empty 538 * match list. Prepares the matching code for use. 539 * 540 * exit: 541 * Returns True (1) if no errors are encountered. Writes an 542 * error string to stderr and returns False (0) otherwise. 543 */ 544 static int 545 match_prepare(char *argv0, uint_t flags) 546 { 547 atoui_sym_t *sym; 548 match_rec_t *list; 549 const char *str; 550 int minus_p = (flags & FLG_SHOW_PHDR) != 0; 551 552 /* 553 * Flag ambiguous attempt to use match option with both -p and 554 * and one or more section SHOW options. In this case, we 555 * can't tell what type of item we're supposed to match against. 556 */ 557 if (minus_p && (flags & FLG_MASK_SHOW_SHDR)) { 558 (void) fprintf(stderr, MSG_INTL(MSG_ERR_AMBIG_MATCH), 559 basename(argv0)); 560 return (0); 561 } 562 563 /* Set the match type, based on the presence of the -p option */ 564 if (minus_p) { 565 match_state.item_type = MATCH_ITEM_PT; 566 sym = sym_pt; 567 } else { 568 match_state.item_type = MATCH_ITEM_SHT; 569 sym = sym_sht; 570 } 571 572 /* 573 * Scan match list and perform any necessary fixups: 574 * 575 * MATCH_OPT_NAME: If -p is specified, convert MATCH_OPT_NAME (-N) 576 * requests into MATCH_OPT_TYPE (-T). 577 * 578 * MATCH_OPT_TYPE: Now that we know item type we are matching 579 * against, we can convert the string saved in the name 580 * field during getopt() processing into an integer and 581 * write it into the type field. 582 */ 583 for (list = match_state.list; list; list = list->next) { 584 if ((list->opt_type == MATCH_OPT_NAME) && minus_p) 585 list->opt_type = MATCH_OPT_TYPE; 586 587 if (list->opt_type != MATCH_OPT_TYPE) 588 continue; 589 590 str = list->value.name; 591 if (atoui(str, sym, &list->value.type) == 0) { 592 const char *fmt = minus_p ? 593 MSG_INTL(MSG_ERR_BAD_T_PT) : 594 MSG_INTL(MSG_ERR_BAD_T_SHT); 595 596 (void) fprintf(stderr, fmt, basename(argv0), str); 597 return (0); 598 } 599 } 600 601 return (1); 602 } 603 604 605 /* 606 * Returns True (1) if the item with the given name or index should 607 * be displayed, and False (0) if it should not be. 608 * 609 * entry: 610 * match_flags - Bitmask specifying matching options, as described 611 * in _elfdump.h. 612 * name - If MATCH_F_NAME flag is set, name of item under 613 * consideration. Otherwise ignored. 614 * should not be considered. 615 * ndx - If MATCH_F_NDX flag is set, index of item under consideration. 616 * type - If MATCH_F_TYPE is set, type of item under consideration. 617 * If MATCH_F_PHDR is set, this would be a program 618 * header type (PT_). Otherwise, a section header type (SHT_). 619 * 620 * exit: 621 * True will be returned if the given name/index matches those given 622 * by one of the (-I, -N -T) command line options, or if no such option 623 * was used in the command invocation and MATCH_F_STRICT is not 624 * set. 625 */ 626 int 627 match(match_flags_t match_flags, const char *name, uint_t ndx, uint_t type) 628 { 629 match_item_t item_type = (match_flags & MATCH_F_PHDR) ? 630 MATCH_ITEM_PT : MATCH_ITEM_SHT; 631 match_rec_t *list; 632 633 /* 634 * If there is no match list, then we use the MATCH_F_STRICT 635 * flag to decide what to return. In the strict case, we return 636 * False (0), in the normal case, True (1). 637 */ 638 if (match_state.list == NULL) 639 return ((match_flags & MATCH_F_STRICT) == 0); 640 641 /* 642 * If item being checked is not the current match type, 643 * then allow it. 644 */ 645 if (item_type != match_state.item_type) 646 return (1); 647 648 /* Run through the match records and check for a hit */ 649 for (list = match_state.list; list; list = list->next) { 650 switch (list->opt_type) { 651 case MATCH_OPT_NAME: 652 if (((match_flags & MATCH_F_NAME) == 0) || 653 (name == NULL)) 654 break; 655 if (strcmp(list->value.name, name) == 0) 656 return (1); 657 break; 658 case MATCH_OPT_NDX: 659 if ((match_flags & MATCH_F_NDX) && 660 (ndx == list->value.ndx.start)) 661 return (1); 662 break; 663 case MATCH_OPT_RANGE: 664 /* 665 * A range end value less than 0 means that any value 666 * above the start is acceptible. 667 */ 668 if ((match_flags & MATCH_F_NDX) && 669 (ndx >= list->value.ndx.start) && 670 ((list->value.ndx.end < 0) || 671 (ndx <= list->value.ndx.end))) 672 return (1); 673 break; 674 675 case MATCH_OPT_TYPE: 676 if ((match_flags & MATCH_F_TYPE) && 677 (type == list->value.type)) 678 return (1); 679 break; 680 } 681 } 682 683 /* Nothing matched */ 684 return (0); 685 } 686 687 /* 688 * Add an entry to match_state.list for use by match(). This routine is for 689 * use during getopt() processing. It should not be called once 690 * match_prepare() has been called. 691 * 692 * Return True (1) for success. On failure, an error is written 693 * to stderr, and False (0) is returned. 694 */ 695 static int 696 add_match_record(char *argv0, match_rec_t *data) 697 { 698 match_rec_t *rec; 699 match_rec_t *list; 700 701 if ((rec = malloc(sizeof (*rec))) == NULL) { 702 int err = errno; 703 (void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC), 704 basename(argv0), strerror(err)); 705 return (0); 706 } 707 708 *rec = *data; 709 710 /* Insert at end of match_state.list */ 711 if (match_state.list == NULL) { 712 match_state.list = rec; 713 } else { 714 for (list = match_state.list; list->next != NULL; 715 list = list->next) 716 ; 717 list->next = rec; 718 } 719 720 rec->next = NULL; 721 return (1); 722 } 723 724 static int 725 decide(const char *file, int fd, Elf *elf, uint_t flags, 726 const char *wname, int wfd) 727 { 728 int r; 729 730 if (gelf_getclass(elf) == ELFCLASS64) 731 r = regular64(file, fd, elf, flags, wname, wfd); 732 else 733 r = regular32(file, fd, elf, flags, wname, wfd); 734 735 return (r); 736 } 737 738 static int 739 archive(const char *file, int fd, Elf *elf, uint_t flags, 740 const char *wname, int wfd) 741 { 742 Elf_Cmd cmd = ELF_C_READ; 743 Elf_Arhdr *arhdr; 744 Elf *_elf = 0; 745 size_t ptr; 746 Elf_Arsym *arsym = 0; 747 748 /* 749 * Determine if the archive symbol table itself is required. 750 */ 751 if ((flags & FLG_SHOW_SYMBOLS) && 752 match(MATCH_F_NAME, MSG_ORIG(MSG_ELF_ARSYM), 0, 0)) { 753 /* 754 * Get the archive symbol table. 755 */ 756 if (((arsym = elf_getarsym(elf, &ptr)) == 0) && elf_errno()) { 757 /* 758 * The arsym could be 0 even though there was no error. 759 * Print the error message only when there was 760 * real error from elf_getarsym(). 761 */ 762 failure(file, MSG_ORIG(MSG_ELF_GETARSYM)); 763 return (0); 764 } 765 } 766 767 /* 768 * Print the archive symbol table only when the archive symbol 769 * table exists and it was requested to print. 770 */ 771 if (arsym) { 772 size_t cnt; 773 char index[MAXNDXSIZE]; 774 size_t offset = 0, _offset = 0; 775 776 /* 777 * Print out all the symbol entries. 778 */ 779 dbg_print(0, MSG_INTL(MSG_ARCHIVE_SYMTAB)); 780 dbg_print(0, MSG_INTL(MSG_ARCHIVE_FIELDS)); 781 782 for (cnt = 0; cnt < ptr; cnt++, arsym++) { 783 /* 784 * For each object obtain an elf descriptor so that we 785 * can establish the members name. Note, we have had 786 * archives where the archive header has not been 787 * obtainable so be lenient with errors. 788 */ 789 if ((offset == 0) || ((arsym->as_off != 0) && 790 (arsym->as_off != _offset))) { 791 792 if (_elf) 793 (void) elf_end(_elf); 794 795 if (elf_rand(elf, arsym->as_off) != 796 arsym->as_off) { 797 failure(file, MSG_ORIG(MSG_ELF_RAND)); 798 arhdr = 0; 799 } else if ((_elf = elf_begin(fd, 800 ELF_C_READ, elf)) == 0) { 801 failure(file, MSG_ORIG(MSG_ELF_BEGIN)); 802 arhdr = 0; 803 } else if ((arhdr = elf_getarhdr(_elf)) == 0) { 804 failure(file, 805 MSG_ORIG(MSG_ELF_GETARHDR)); 806 arhdr = 0; 807 } 808 809 _offset = arsym->as_off; 810 if (offset == 0) 811 offset = _offset; 812 } 813 814 (void) snprintf(index, MAXNDXSIZE, 815 MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(cnt)); 816 if (arsym->as_off) 817 dbg_print(0, MSG_ORIG(MSG_FMT_ARSYM1), index, 818 /* LINTED */ 819 (int)arsym->as_off, arhdr ? arhdr->ar_name : 820 MSG_INTL(MSG_STR_UNKNOWN), (arsym->as_name ? 821 demangle(arsym->as_name, flags) : 822 MSG_INTL(MSG_STR_NULL))); 823 else 824 dbg_print(0, MSG_ORIG(MSG_FMT_ARSYM2), index, 825 /* LINTED */ 826 (int)arsym->as_off); 827 } 828 829 if (_elf) 830 (void) elf_end(_elf); 831 832 /* 833 * If we only need the archive symbol table return. 834 */ 835 if ((flags & FLG_SHOW_SYMBOLS) && 836 match(MATCH_F_STRICT | MATCH_F_NAME, 837 MSG_ORIG(MSG_ELF_ARSYM), -1, -1)) 838 return (0); 839 840 /* 841 * Reset elf descriptor in preparation for processing each 842 * member. 843 */ 844 if (offset) 845 (void) elf_rand(elf, offset); 846 } 847 848 /* 849 * Process each object within the archive. 850 */ 851 while ((_elf = elf_begin(fd, cmd, elf)) != NULL) { 852 char name[MAXPATHLEN]; 853 854 if ((arhdr = elf_getarhdr(_elf)) == NULL) { 855 failure(file, MSG_ORIG(MSG_ELF_GETARHDR)); 856 return (0); 857 } 858 if (*arhdr->ar_name != '/') { 859 (void) snprintf(name, MAXPATHLEN, 860 MSG_ORIG(MSG_FMT_ARNAME), file, arhdr->ar_name); 861 dbg_print(0, MSG_ORIG(MSG_FMT_NLSTR), name); 862 863 switch (elf_kind(_elf)) { 864 case ELF_K_AR: 865 if (archive(name, fd, _elf, flags, 866 wname, wfd) == 1) 867 return (1); 868 break; 869 case ELF_K_ELF: 870 if (decide(name, fd, _elf, flags, 871 wname, wfd) == 1) 872 return (1); 873 break; 874 default: 875 (void) fprintf(stderr, 876 MSG_INTL(MSG_ERR_BADFILE), name); 877 break; 878 } 879 } 880 881 cmd = elf_next(_elf); 882 (void) elf_end(_elf); 883 } 884 885 return (0); 886 } 887 888 int 889 main(int argc, char **argv, char **envp) 890 { 891 Elf *elf; 892 int var, fd, wfd = 0; 893 char *wname = NULL; 894 uint_t flags = 0; 895 match_rec_t match_data; 896 int ret; 897 898 /* 899 * If we're on a 64-bit kernel, try to exec a full 64-bit version of 900 * the binary. If successful, conv_check_native() won't return. 901 */ 902 (void) conv_check_native(argv, envp); 903 904 /* 905 * Establish locale. 906 */ 907 (void) setlocale(LC_MESSAGES, MSG_ORIG(MSG_STR_EMPTY)); 908 (void) textdomain(MSG_ORIG(MSG_SUNW_OST_SGS)); 909 910 (void) setvbuf(stdout, NULL, _IOLBF, 0); 911 (void) setvbuf(stderr, NULL, _IOLBF, 0); 912 913 opterr = 0; 914 while ((var = getopt(argc, argv, MSG_ORIG(MSG_STR_OPTIONS))) != EOF) { 915 switch (var) { 916 case 'C': 917 flags |= FLG_CTL_DEMANGLE; 918 break; 919 case 'c': 920 flags |= FLG_SHOW_SHDR; 921 break; 922 case 'd': 923 flags |= FLG_SHOW_DYNAMIC; 924 break; 925 case 'e': 926 flags |= FLG_SHOW_EHDR; 927 break; 928 case 'G': 929 flags |= FLG_SHOW_GOT; 930 break; 931 case 'g': 932 flags |= FLG_SHOW_GROUP; 933 break; 934 case 'H': 935 flags |= FLG_SHOW_CAP; 936 break; 937 case 'h': 938 flags |= FLG_SHOW_HASH; 939 break; 940 case 'I': 941 if (!process_index_opt(optarg, &match_data)) 942 goto usage_brief; 943 if (!add_match_record(argv[0], &match_data)) 944 return (1); 945 flags |= FLG_CTL_MATCH; 946 break; 947 case 'i': 948 flags |= FLG_SHOW_INTERP; 949 break; 950 case 'k': 951 flags |= FLG_CALC_CHECKSUM; 952 break; 953 case 'l': 954 flags |= FLG_CTL_LONGNAME; 955 break; 956 case 'm': 957 flags |= FLG_SHOW_MOVE; 958 break; 959 case 'N': 960 match_data.opt_type = MATCH_OPT_NAME; 961 match_data.value.name = optarg; 962 if (!add_match_record(argv[0], &match_data)) 963 return (1); 964 flags |= FLG_CTL_MATCH; 965 break; 966 case 'n': 967 flags |= FLG_SHOW_NOTE; 968 break; 969 case 'P': 970 flags |= FLG_CTL_FAKESHDR; 971 break; 972 case 'p': 973 flags |= FLG_SHOW_PHDR; 974 break; 975 case 'r': 976 flags |= FLG_SHOW_RELOC; 977 break; 978 case 'S': 979 flags |= FLG_SHOW_SORT; 980 break; 981 case 's': 982 flags |= FLG_SHOW_SYMBOLS; 983 break; 984 case 'T': 985 /* 986 * We can't evaluate the value yet, because 987 * we need to know if -p is used or not in 988 * order to tell if we're seeing section header 989 * or program header types. So, we save the 990 * string in the name field, and then convert 991 * it to a type integer in a following pass. 992 */ 993 match_data.opt_type = MATCH_OPT_TYPE; 994 match_data.value.name = optarg; 995 if (!add_match_record(argv[0], &match_data)) 996 return (1); 997 flags |= FLG_CTL_MATCH; 998 break; 999 case 'u': 1000 flags |= FLG_SHOW_UNWIND; 1001 break; 1002 case 'v': 1003 flags |= FLG_SHOW_VERSIONS; 1004 break; 1005 case 'w': 1006 wname = optarg; 1007 break; 1008 case 'y': 1009 flags |= FLG_SHOW_SYMINFO; 1010 break; 1011 case '?': 1012 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF), 1013 basename(argv[0])); 1014 detail_usage(); 1015 return (1); 1016 default: 1017 break; 1018 } 1019 } 1020 1021 /* -p and -w are mutually exclusive. -w only works with sections */ 1022 if (((flags & FLG_SHOW_PHDR) != 0) && (wname != NULL)) 1023 goto usage_brief; 1024 1025 /* If a match argument is present, prepare the match state */ 1026 if ((match_state.list != NULL) && (match_prepare(argv[0], flags) == 0)) 1027 return (1); 1028 1029 /* 1030 * Decide what to do if no options specifying something to 1031 * show or do are present. 1032 * 1033 * If there is no -w and no match options, then we will set all 1034 * the show flags, causing a full display of everything in the 1035 * file that we know how to handle. 1036 * 1037 * Otherwise, if there is no match list, we generate a usage 1038 * error and quit. 1039 * 1040 * In the case where there is a match list, we go ahead and call 1041 * regular() anyway, leaving it to decide what to do. If -w is 1042 * present, regular() will use the match list to handle it. 1043 * In addition, in the absence of explicit show/calc flags, regular() 1044 * will compare the section headers to the match list and use 1045 * that to generate the FLG_ bits that will display the information 1046 * specified by the match list. 1047 */ 1048 if ((flags & ~FLG_MASK_CTL) == 0) { 1049 if (!wname && (match_state.list == NULL)) 1050 flags |= FLG_MASK_SHOW; 1051 else if (match_state.list == NULL) 1052 goto usage_brief; 1053 } 1054 1055 /* There needs to be at least 1 filename left following the options */ 1056 if ((var = argc - optind) == 0) 1057 goto usage_brief; 1058 1059 /* 1060 * If the -l/-C option is specified, set up the liblddbg.so. 1061 */ 1062 if (flags & FLG_CTL_LONGNAME) 1063 dbg_desc->d_extra |= DBG_E_LONG; 1064 if (flags & FLG_CTL_DEMANGLE) 1065 dbg_desc->d_extra |= DBG_E_DEMANGLE; 1066 1067 /* 1068 * If the -w option has indicated an output file open it. It's 1069 * arguable whether this option has much use when multiple files are 1070 * being processed. 1071 * 1072 * If wname is non-NULL, we know that -p was not specified, due 1073 * to the test above. 1074 */ 1075 if (wname) { 1076 if ((wfd = open(wname, (O_RDWR | O_CREAT | O_TRUNC), 1077 0666)) < 0) { 1078 int err = errno; 1079 (void) fprintf(stderr, MSG_INTL(MSG_ERR_OPEN), 1080 wname, strerror(err)); 1081 return (1); 1082 } 1083 } 1084 1085 /* 1086 * Open the input file, initialize the elf interface, and 1087 * process it. 1088 */ 1089 ret = 0; 1090 for (; (optind < argc) && (ret == 0); optind++) { 1091 const char *file = argv[optind]; 1092 1093 if ((fd = open(argv[optind], O_RDONLY)) == -1) { 1094 int err = errno; 1095 (void) fprintf(stderr, MSG_INTL(MSG_ERR_OPEN), 1096 file, strerror(err)); 1097 continue; 1098 } 1099 (void) elf_version(EV_CURRENT); 1100 if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { 1101 failure(file, MSG_ORIG(MSG_ELF_BEGIN)); 1102 (void) close(fd); 1103 continue; 1104 } 1105 1106 if (var > 1) 1107 dbg_print(0, MSG_ORIG(MSG_FMT_NLSTRNL), file); 1108 1109 switch (elf_kind(elf)) { 1110 case ELF_K_AR: 1111 ret = archive(file, fd, elf, flags, wname, wfd); 1112 break; 1113 case ELF_K_ELF: 1114 ret = decide(file, fd, elf, flags, wname, wfd); 1115 break; 1116 default: 1117 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADFILE), file); 1118 break; 1119 } 1120 1121 (void) close(fd); 1122 (void) elf_end(elf); 1123 } 1124 1125 if (wfd) 1126 (void) close(wfd); 1127 return (ret); 1128 1129 usage_brief: 1130 /* Control comes here for a simple usage message and exit */ 1131 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF), 1132 basename(argv[0])); 1133 return (1); 1134 1135 } 1136