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