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 2007 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 * Convert the ASCII representation of an index, or index range, into 335 * binary form, and store it in rec: 336 * 337 * index: An positive or 0 valued integer 338 * range: Two indexes, separated by a ':' character, denoting 339 * a range of allowed values. If the second value is omitted, 340 * any values equal to or greater than the first will match. 341 * 342 * exit: 343 * On success, *rec is filled in with a MATCH_OPT_NDX or MATCH_OPT_RANGE 344 * value, and this function returns (1). On failure, the contents 345 * of *rec are undefined, and (0) is returned. 346 */ 347 int 348 process_index_opt(const char *str, match_rec_t *rec) 349 { 350 #define SKIP_BLANK for (; *str && isspace(*str); str++) 351 352 char *endptr; 353 354 rec->value.ndx.start = strtol(str, &endptr, 10); 355 /* Value must use some of the input, and be 0 or positive */ 356 if ((str == endptr) || (rec->value.ndx.start < 0)) 357 return (0); 358 str = endptr; 359 360 SKIP_BLANK; 361 if (*str != ':') { 362 rec->opt_type = MATCH_OPT_NDX; 363 } else { 364 str++; /* Skip the ':' */ 365 rec->opt_type = MATCH_OPT_RANGE; 366 SKIP_BLANK; 367 if (*str == '\0') { 368 rec->value.ndx.end = -1; /* Indicates "to end" */ 369 } else { 370 rec->value.ndx.end = strtol(str, &endptr, 10); 371 if ((str == endptr) || (rec->value.ndx.end < 0)) 372 return (0); 373 str = endptr; 374 SKIP_BLANK; 375 } 376 } 377 378 /* Syntax error if anything is left over */ 379 if (*str != '\0') 380 return (0); 381 382 return (1); 383 384 #undef SKIP_BLANK 385 } 386 387 /* 388 * Process the symbolic name to value mappings passed to the 389 * atoui() function. 390 * 391 * entry: 392 * sym - NULL terminated array of name->value mappings. 393 * value - Address of variable to receive corresponding value. 394 * 395 * exit: 396 * If a mapping is found, *value is set to it, and True is returned. 397 * Otherwise False is returned. 398 */ 399 static int 400 atoui_sym_process(const char *str, const atoui_sym_t *sym, uint32_t *value) 401 { 402 size_t cmp_len; 403 const char *tail; 404 405 while (isspace(*str)) 406 str++; 407 408 tail = str + strlen(str); 409 while ((tail > str) && isspace(*(tail - 1))) 410 tail--; 411 412 cmp_len = tail - str; 413 414 for (; sym->sym_name != NULL; sym++) { 415 if ((strlen(sym->sym_name) == cmp_len) && 416 (strncasecmp(sym->sym_name, str, cmp_len) == 0)) { 417 *value = sym->sym_value; 418 return (1); 419 } 420 } 421 422 /* No symbolic mapping was found */ 423 return (0); 424 } 425 426 427 /* 428 * Convert a string to a numeric value. Strings starting with '0' 429 * are taken to be octal, those staring with '0x' are hex, and all 430 * others are decimal. 431 * 432 * entry: 433 * str - String to be converted 434 * sym - NULL, or NULL terminated array of name/value pairs. 435 * v - Address of variable to receive resulting value. 436 * 437 * exit: 438 * On success, returns True (1) and *v is set to the value. 439 * On failure, returns False (0) and *v is undefined. 440 */ 441 static int 442 atoui(const char *str, const atoui_sym_t *sym, uint32_t *v) 443 { 444 char *endptr; 445 446 if (sym && atoui_sym_process(str, sym, v)) 447 return (1); 448 449 *v = strtoull(str, &endptr, 0); 450 451 /* If the left over part contains anything but whitespace, fail */ 452 for (; *endptr; endptr++) 453 if (!isspace(*endptr)) 454 return (0); 455 return (1); 456 } 457 458 /* 459 * Called after getopt() processing is finished if there is a non-empty 460 * match list. Prepares the matching code for use. 461 * 462 * exit: 463 * Returns True (1) if no errors are encountered. Writes an 464 * error string to stderr and returns False (0) otherwise. 465 */ 466 static int 467 match_prepare(char *argv0, uint_t flags) 468 { 469 atoui_sym_t *sym; 470 match_rec_t *list; 471 const char *str; 472 int minus_p = (flags & FLG_SHOW_PHDR) != 0; 473 474 /* 475 * Flag ambiguous attempt to use match option with both -p and 476 * and one or more section SHOW options. In this case, we 477 * can't tell what type of item we're supposed to match against. 478 */ 479 if (minus_p && (flags & FLG_MASK_SHOW_SHDR)) { 480 (void) fprintf(stderr, MSG_INTL(MSG_ERR_AMBIG_MATCH), 481 basename(argv0)); 482 return (0); 483 } 484 485 /* Set the match type, based on the presence of the -p option */ 486 if (minus_p) { 487 match_state.item_type = MATCH_ITEM_PT; 488 sym = sym_pt; 489 } else { 490 match_state.item_type = MATCH_ITEM_SHT; 491 sym = sym_sht; 492 } 493 494 /* 495 * Scan match list and perform any necessary fixups: 496 * 497 * MATCH_OPT_NAME: If -p is specified, convert MATCH_OPT_NAME (-N) 498 * requests into MATCH_OPT_TYPE (-T). 499 * 500 * MATCH_OPT_TYPE: Now that we know item type we are matching 501 * against, we can convert the string saved in the name 502 * field during getopt() processing into an integer and 503 * write it into the type field. 504 */ 505 for (list = match_state.list; list; list = list->next) { 506 if ((list->opt_type == MATCH_OPT_NAME) && minus_p) 507 list->opt_type = MATCH_OPT_TYPE; 508 509 if (list->opt_type != MATCH_OPT_TYPE) 510 continue; 511 512 str = list->value.name; 513 if (atoui(str, sym, &list->value.type) == 0) { 514 const char *fmt = minus_p ? 515 MSG_INTL(MSG_ERR_BAD_T_PT) : 516 MSG_INTL(MSG_ERR_BAD_T_SHT); 517 518 (void) fprintf(stderr, fmt, basename(argv0), str); 519 return (0); 520 } 521 } 522 523 return (1); 524 } 525 526 527 /* 528 * Returns True (1) if the item with the given name or index should 529 * be displayed, and False (0) if it should not be. 530 * 531 * entry: 532 * match_flags - Bitmask specifying matching options, as described 533 * in _elfdump.h. 534 * name - If MATCH_F_NAME flag is set, name of item under 535 * consideration. Otherwise ignored. 536 * should not be considered. 537 * ndx - If MATCH_F_NDX flag is set, index of item under consideration. 538 * type - If MATCH_F_TYPE is set, type of item under consideration. 539 * If MATCH_F_PHDR is set, this would be a program 540 * header type (PT_). Otherwise, a section header type (SHT_). 541 * 542 * exit: 543 * True will be returned if the given name/index matches those given 544 * by one of the (-I, -N -T) command line options, or if no such option 545 * was used in the command invocation and MATCH_F_STRICT is not 546 * set. 547 */ 548 int 549 match(match_flags_t match_flags, const char *name, uint_t ndx, uint_t type) 550 { 551 match_item_t item_type = (match_flags & MATCH_F_PHDR) ? 552 MATCH_ITEM_PT : MATCH_ITEM_SHT; 553 match_rec_t *list; 554 555 /* 556 * If there is no match list, then we use the MATCH_F_STRICT 557 * flag to decide what to return. In the strict case, we return 558 * False (0), in the normal case, True (1). 559 */ 560 if (match_state.list == NULL) 561 return ((match_flags & MATCH_F_STRICT) == 0); 562 563 /* 564 * If item being checked is not the current match type, 565 * then allow it. 566 */ 567 if (item_type != match_state.item_type) 568 return (1); 569 570 /* Run through the match records and check for a hit */ 571 for (list = match_state.list; list; list = list->next) { 572 switch (list->opt_type) { 573 case MATCH_OPT_NAME: 574 if (((match_flags & MATCH_F_NAME) == 0) || 575 (name == NULL)) 576 break; 577 if (strcmp(list->value.name, name) == 0) 578 return (1); 579 break; 580 case MATCH_OPT_NDX: 581 if ((match_flags & MATCH_F_NDX) && 582 (ndx == list->value.ndx.start)) 583 return (1); 584 break; 585 case MATCH_OPT_RANGE: 586 /* 587 * A range end value less than 0 means that any value 588 * above the start is acceptible. 589 */ 590 if ((match_flags & MATCH_F_NDX) && 591 (ndx >= list->value.ndx.start) && 592 ((list->value.ndx.end < 0) || 593 (ndx <= list->value.ndx.end))) 594 return (1); 595 break; 596 597 case MATCH_OPT_TYPE: 598 if ((match_flags & MATCH_F_TYPE) && 599 (type == list->value.type)) 600 return (1); 601 break; 602 } 603 } 604 605 /* Nothing matched */ 606 return (0); 607 } 608 609 /* 610 * Add an entry to match_state.list for use by match(). This routine is for 611 * use during getopt() processing. It should not be called once 612 * match_prepare() has been called. 613 * 614 * Return True (1) for success. On failure, an error is written 615 * to stderr, and False (0) is returned. 616 */ 617 static int 618 add_match_record(char *argv0, match_rec_t *data) 619 { 620 match_rec_t *rec; 621 match_rec_t *list; 622 623 if ((rec = malloc(sizeof (*rec))) == NULL) { 624 int err = errno; 625 (void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC), 626 basename(argv0), strerror(err)); 627 return (0); 628 } 629 630 *rec = *data; 631 632 /* Insert at end of match_state.list */ 633 if (match_state.list == NULL) { 634 match_state.list = rec; 635 } else { 636 for (list = match_state.list; list->next != NULL; 637 list = list->next) 638 ; 639 list->next = rec; 640 } 641 642 rec->next = NULL; 643 return (1); 644 } 645 646 static int 647 decide(const char *file, int fd, Elf *elf, uint_t flags, 648 const char *wname, int wfd) 649 { 650 int r; 651 652 if (gelf_getclass(elf) == ELFCLASS64) 653 r = regular64(file, fd, elf, flags, wname, wfd); 654 else 655 r = regular32(file, fd, elf, flags, wname, wfd); 656 657 return (r); 658 } 659 660 static int 661 archive(const char *file, int fd, Elf *elf, uint_t flags, 662 const char *wname, int wfd) 663 { 664 Elf_Cmd cmd = ELF_C_READ; 665 Elf_Arhdr *arhdr; 666 Elf *_elf = 0; 667 size_t ptr; 668 Elf_Arsym *arsym = 0; 669 670 /* 671 * Determine if the archive symbol table itself is required. 672 */ 673 if ((flags & FLG_SHOW_SYMBOLS) && 674 match(MATCH_F_NAME, MSG_ORIG(MSG_ELF_ARSYM), 0, 0)) { 675 /* 676 * Get the archive symbol table. 677 */ 678 if (((arsym = elf_getarsym(elf, &ptr)) == 0) && elf_errno()) { 679 /* 680 * The arsym could be 0 even though there was no error. 681 * Print the error message only when there was 682 * real error from elf_getarsym(). 683 */ 684 failure(file, MSG_ORIG(MSG_ELF_GETARSYM)); 685 return (0); 686 } 687 } 688 689 /* 690 * Print the archive symbol table only when the archive symbol 691 * table exists and it was requested to print. 692 */ 693 if (arsym) { 694 size_t cnt; 695 char index[MAXNDXSIZE]; 696 size_t offset = 0, _offset = 0; 697 698 /* 699 * Print out all the symbol entries. 700 */ 701 dbg_print(0, MSG_INTL(MSG_ARCHIVE_SYMTAB)); 702 dbg_print(0, MSG_INTL(MSG_ARCHIVE_FIELDS)); 703 704 for (cnt = 0; cnt < ptr; cnt++, arsym++) { 705 /* 706 * For each object obtain an elf descriptor so that we 707 * can establish the members name. Note, we have had 708 * archives where the archive header has not been 709 * obtainable so be lenient with errors. 710 */ 711 if ((offset == 0) || ((arsym->as_off != 0) && 712 (arsym->as_off != _offset))) { 713 714 if (_elf) 715 (void) elf_end(_elf); 716 717 if (elf_rand(elf, arsym->as_off) != 718 arsym->as_off) { 719 failure(file, MSG_ORIG(MSG_ELF_RAND)); 720 arhdr = 0; 721 } else if ((_elf = elf_begin(fd, 722 ELF_C_READ, elf)) == 0) { 723 failure(file, MSG_ORIG(MSG_ELF_BEGIN)); 724 arhdr = 0; 725 } else if ((arhdr = elf_getarhdr(_elf)) == 0) { 726 failure(file, 727 MSG_ORIG(MSG_ELF_GETARHDR)); 728 arhdr = 0; 729 } 730 731 _offset = arsym->as_off; 732 if (offset == 0) 733 offset = _offset; 734 } 735 736 (void) snprintf(index, MAXNDXSIZE, 737 MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(cnt)); 738 if (arsym->as_off) 739 dbg_print(0, MSG_ORIG(MSG_FMT_ARSYM1), index, 740 /* LINTED */ 741 (int)arsym->as_off, arhdr ? arhdr->ar_name : 742 MSG_INTL(MSG_STR_UNKNOWN), (arsym->as_name ? 743 demangle(arsym->as_name, flags) : 744 MSG_INTL(MSG_STR_NULL))); 745 else 746 dbg_print(0, MSG_ORIG(MSG_FMT_ARSYM2), index, 747 /* LINTED */ 748 (int)arsym->as_off); 749 } 750 751 if (_elf) 752 (void) elf_end(_elf); 753 754 /* 755 * If we only need the archive symbol table return. 756 */ 757 if ((flags & FLG_SHOW_SYMBOLS) && 758 match(MATCH_F_STRICT | MATCH_F_NAME, 759 MSG_ORIG(MSG_ELF_ARSYM), -1, -1)) 760 return (0); 761 762 /* 763 * Reset elf descriptor in preparation for processing each 764 * member. 765 */ 766 if (offset) 767 (void) elf_rand(elf, offset); 768 } 769 770 /* 771 * Process each object within the archive. 772 */ 773 while ((_elf = elf_begin(fd, cmd, elf)) != NULL) { 774 char name[MAXPATHLEN]; 775 776 if ((arhdr = elf_getarhdr(_elf)) == NULL) { 777 failure(file, MSG_ORIG(MSG_ELF_GETARHDR)); 778 return (0); 779 } 780 if (*arhdr->ar_name != '/') { 781 (void) snprintf(name, MAXPATHLEN, 782 MSG_ORIG(MSG_FMT_ARNAME), file, arhdr->ar_name); 783 dbg_print(0, MSG_ORIG(MSG_FMT_NLSTR), name); 784 785 switch (elf_kind(_elf)) { 786 case ELF_K_AR: 787 if (archive(name, fd, _elf, flags, 788 wname, wfd) == 1) 789 return (1); 790 break; 791 case ELF_K_ELF: 792 if (decide(name, fd, _elf, flags, 793 wname, wfd) == 1) 794 return (1); 795 break; 796 default: 797 (void) fprintf(stderr, 798 MSG_INTL(MSG_ERR_BADFILE), name); 799 break; 800 } 801 } 802 803 cmd = elf_next(_elf); 804 (void) elf_end(_elf); 805 } 806 807 return (0); 808 } 809 810 int 811 main(int argc, char **argv, char **envp) 812 { 813 Elf *elf; 814 int var, fd, wfd = 0; 815 char *wname = NULL; 816 uint_t flags = 0; 817 match_rec_t match_data; 818 int ret; 819 820 /* 821 * If we're on a 64-bit kernel, try to exec a full 64-bit version of 822 * the binary. If successful, conv_check_native() won't return. 823 */ 824 (void) conv_check_native(argv, envp); 825 826 /* 827 * Establish locale. 828 */ 829 (void) setlocale(LC_MESSAGES, MSG_ORIG(MSG_STR_EMPTY)); 830 (void) textdomain(MSG_ORIG(MSG_SUNW_OST_SGS)); 831 832 (void) setvbuf(stdout, NULL, _IOLBF, 0); 833 (void) setvbuf(stderr, NULL, _IOLBF, 0); 834 835 opterr = 0; 836 while ((var = getopt(argc, argv, MSG_ORIG(MSG_STR_OPTIONS))) != EOF) { 837 switch (var) { 838 case 'C': 839 flags |= FLG_CTL_DEMANGLE; 840 break; 841 case 'c': 842 flags |= FLG_SHOW_SHDR; 843 break; 844 case 'd': 845 flags |= FLG_SHOW_DYNAMIC; 846 break; 847 case 'e': 848 flags |= FLG_SHOW_EHDR; 849 break; 850 case 'G': 851 flags |= FLG_SHOW_GOT; 852 break; 853 case 'g': 854 flags |= FLG_SHOW_GROUP; 855 break; 856 case 'H': 857 flags |= FLG_SHOW_CAP; 858 break; 859 case 'h': 860 flags |= FLG_SHOW_HASH; 861 break; 862 case 'I': 863 if (!process_index_opt(optarg, &match_data)) 864 goto usage_brief; 865 if (!add_match_record(argv[0], &match_data)) 866 return (1); 867 flags |= FLG_CTL_MATCH; 868 break; 869 case 'i': 870 flags |= FLG_SHOW_INTERP; 871 break; 872 case 'k': 873 flags |= FLG_CALC_CHECKSUM; 874 break; 875 case 'l': 876 flags |= FLG_CTL_LONGNAME; 877 break; 878 case 'm': 879 flags |= FLG_SHOW_MOVE; 880 break; 881 case 'N': 882 match_data.opt_type = MATCH_OPT_NAME; 883 match_data.value.name = optarg; 884 if (!add_match_record(argv[0], &match_data)) 885 return (1); 886 flags |= FLG_CTL_MATCH; 887 break; 888 case 'n': 889 flags |= FLG_SHOW_NOTE; 890 break; 891 case 'P': 892 flags |= FLG_CTL_FAKESHDR; 893 break; 894 case 'p': 895 flags |= FLG_SHOW_PHDR; 896 break; 897 case 'r': 898 flags |= FLG_SHOW_RELOC; 899 break; 900 case 'S': 901 flags |= FLG_SHOW_SORT; 902 break; 903 case 's': 904 flags |= FLG_SHOW_SYMBOLS; 905 break; 906 case 'T': 907 /* 908 * We can't evaluate the value yet, because 909 * we need to know if -p is used or not in 910 * order to tell if we're seeing section header 911 * or program header types. So, we save the 912 * string in the name field, and then convert 913 * it to a type integer in a following pass. 914 */ 915 match_data.opt_type = MATCH_OPT_TYPE; 916 match_data.value.name = optarg; 917 if (!add_match_record(argv[0], &match_data)) 918 return (1); 919 flags |= FLG_CTL_MATCH; 920 break; 921 case 'u': 922 flags |= FLG_SHOW_UNWIND; 923 break; 924 case 'v': 925 flags |= FLG_SHOW_VERSIONS; 926 break; 927 case 'w': 928 wname = optarg; 929 break; 930 case 'y': 931 flags |= FLG_SHOW_SYMINFO; 932 break; 933 case '?': 934 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF), 935 basename(argv[0])); 936 detail_usage(); 937 return (1); 938 default: 939 break; 940 } 941 } 942 943 /* -p and -w are mutually exclusive. -w only works with sections */ 944 if (((flags & FLG_SHOW_PHDR) != 0) && (wname != NULL)) 945 goto usage_brief; 946 947 /* If a match argument is present, prepare the match state */ 948 if ((match_state.list != NULL) && (match_prepare(argv[0], flags) == 0)) 949 return (1); 950 951 /* 952 * Decide what to do if no options specifying something to 953 * show or do are present. 954 * 955 * If there is no -w and no match options, then we will set all 956 * the show flags, causing a full display of everything in the 957 * file that we know how to handle. 958 * 959 * Otherwise, if there is no match list, we generate a usage 960 * error and quit. 961 * 962 * In the case where there is a match list, we go ahead and call 963 * regular() anyway, leaving it to decide what to do. If -w is 964 * present, regular() will use the match list to handle it. 965 * In addition, in the absence of explicit show/calc flags, regular() 966 * will compare the section headers to the match list and use 967 * that to generate the FLG_ bits that will display the information 968 * specified by the match list. 969 */ 970 if ((flags & ~FLG_MASK_CTL) == 0) { 971 if (!wname && (match_state.list == NULL)) 972 flags |= FLG_MASK_SHOW; 973 else if (match_state.list == NULL) 974 goto usage_brief; 975 } 976 977 /* There needs to be at least 1 filename left following the options */ 978 if ((var = argc - optind) == 0) 979 goto usage_brief; 980 981 /* 982 * If the -l/-C option is specified, set up the liblddbg.so. 983 */ 984 if (flags & FLG_CTL_LONGNAME) 985 dbg_desc->d_extra |= DBG_E_LONG; 986 if (flags & FLG_CTL_DEMANGLE) 987 dbg_desc->d_extra |= DBG_E_DEMANGLE; 988 989 /* 990 * If the -w option has indicated an output file open it. It's 991 * arguable whether this option has much use when multiple files are 992 * being processed. 993 * 994 * If wname is non-NULL, we know that -p was not specified, due 995 * to the test above. 996 */ 997 if (wname) { 998 if ((wfd = open(wname, (O_RDWR | O_CREAT | O_TRUNC), 999 0666)) < 0) { 1000 int err = errno; 1001 (void) fprintf(stderr, MSG_INTL(MSG_ERR_OPEN), 1002 wname, strerror(err)); 1003 return (1); 1004 } 1005 } 1006 1007 /* 1008 * Open the input file, initialize the elf interface, and 1009 * process it. 1010 */ 1011 ret = 0; 1012 for (; (optind < argc) && (ret == 0); optind++) { 1013 const char *file = argv[optind]; 1014 1015 if ((fd = open(argv[optind], O_RDONLY)) == -1) { 1016 int err = errno; 1017 (void) fprintf(stderr, MSG_INTL(MSG_ERR_OPEN), 1018 file, strerror(err)); 1019 continue; 1020 } 1021 (void) elf_version(EV_CURRENT); 1022 if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { 1023 failure(file, MSG_ORIG(MSG_ELF_BEGIN)); 1024 (void) close(fd); 1025 continue; 1026 } 1027 1028 if (var > 1) 1029 dbg_print(0, MSG_ORIG(MSG_FMT_NLSTRNL), file); 1030 1031 switch (elf_kind(elf)) { 1032 case ELF_K_AR: 1033 ret = archive(file, fd, elf, flags, wname, wfd); 1034 break; 1035 case ELF_K_ELF: 1036 ret = decide(file, fd, elf, flags, wname, wfd); 1037 break; 1038 default: 1039 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADFILE), file); 1040 break; 1041 } 1042 1043 (void) close(fd); 1044 (void) elf_end(elf); 1045 } 1046 1047 if (wfd) 1048 (void) close(wfd); 1049 return (ret); 1050 1051 usage_brief: 1052 /* Control comes here for a simple usage message and exit */ 1053 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF), 1054 basename(argv[0])); 1055 return (1); 1056 1057 } 1058