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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 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 <libelf.h> 35 #include <gelf.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 <sys/elf_SPARC.h> 45 #include <sys/elf_386.h> 46 #include <sys/elf_amd64.h> 47 #include <debug.h> 48 #include <_debug.h> 49 #include <conv.h> 50 #include <msg.h> 51 #include <dwarf.h> 52 53 #define FLG_DYNAMIC 0x00000001 54 #define FLG_EHDR 0x00000002 55 #define FLG_INTERP 0x00000004 56 #define FLG_SHDR 0x00000008 57 #define FLG_NOTE 0x00000010 58 #define FLG_PHDR 0x00000020 59 #define FLG_RELOC 0x00000040 60 #define FLG_SYMBOLS 0x00000080 61 #define FLG_VERSIONS 0x00000100 62 #define FLG_HASH 0x00000200 63 #define FLG_GOT 0x00000400 64 #define FLG_SYMINFO 0x00000800 65 #define FLG_MOVE 0x00001000 66 #define FLG_GROUP 0x00002000 67 #define FLG_CAP 0x00004000 68 #define FLG_UNWIND 0x00008000 69 #define FLG_LONGNAME 0x00100000 /* not done by default */ 70 #define FLG_CHECKSUM 0x00200000 /* not done by default */ 71 #define FLG_DEMANGLE 0x00400000 /* not done by default */ 72 73 #define FLG_EVERYTHING 0x000fffff 74 75 #define IAM_SPARC(X) \ 76 ((X == EM_SPARC) || (X == EM_SPARC32PLUS) || (X == EM_SPARCV9)) 77 #define IAM_INTEL(X) \ 78 (X == EM_386) 79 80 #define MAXNDXSIZE 10 81 82 typedef struct cache { 83 GElf_Shdr c_shdr; 84 Elf_Data *c_data; 85 char *c_name; 86 } Cache; 87 88 typedef struct got_info { 89 GElf_Word g_rshtype; /* it will never happen, but */ 90 /* support mixed relocations */ 91 GElf_Rela g_rela; 92 const char *g_symname; 93 } Got_info; 94 95 static const Cache _cache_init = {{0}, NULL, NULL}; 96 97 const char * 98 _elfdump_msg(Msg mid) 99 { 100 return (gettext(MSG_ORIG(mid))); 101 } 102 103 /* 104 * Determine whether a symbol name should be demangled. 105 */ 106 static const char * 107 demangle(const char *name, uint32_t flags) 108 { 109 if (flags & FLG_DEMANGLE) 110 return (Gelf_sym_dem(name)); 111 else 112 return ((char *)name); 113 } 114 115 116 /* 117 * Define our own printing routine. All Elf routines referenced call upon 118 * this routine to carry out the actual printing. 119 */ 120 /*PRINTFLIKE1*/ 121 void 122 dbg_print(const char *format, ...) 123 { 124 va_list ap; 125 126 va_start(ap, format); 127 (void) vprintf(format, ap); 128 (void) printf(MSG_ORIG(MSG_STR_NL)); 129 va_end(ap); 130 } 131 132 /* 133 * Just like dbg_print - except that it does not insert 134 * a newline at the end. Can be used for printing tables 135 * and such. 136 */ 137 /*PRINTFLIKE1*/ 138 void 139 dbg_printf(const char *format, ...) 140 { 141 va_list ap; 142 va_start(ap, format); 143 (void) vprintf(format, ap); 144 va_end(ap); 145 } 146 147 148 149 /* 150 * Define our own standard error routine. 151 */ 152 static void 153 failure(const char *file, const char *func) 154 { 155 (void) fprintf(stderr, MSG_INTL(MSG_ERR_FAILURE), 156 file, func, elf_errmsg(elf_errno())); 157 (void) fflush(stderr); 158 } 159 160 161 /* 162 * Focal point for verifying symbol names. 163 */ 164 static const char * 165 string(Cache *refsec, GElf_Word ndx, Cache *strsec, const char *file, 166 ulong_t name) 167 { 168 static Cache *osec = 0; 169 static int nostr; 170 171 const char *strs = (char *)strsec->c_data->d_buf; 172 ulong_t strn = strsec->c_data->d_size; 173 174 /* 175 * Only print a diagnoistic regarding an empty string table once per 176 * input section being processed. 177 */ 178 if (osec != refsec) { 179 osec = refsec; 180 nostr = 0; 181 } 182 183 /* 184 * Is the string table offset within range of the available strings? 185 */ 186 if (name >= strn) { 187 /* 188 * Do we have a empty string table? 189 */ 190 if (strs == 0) { 191 if (nostr == 0) { 192 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 193 file, strsec->c_name); 194 (void) fflush(stderr); 195 nostr++; 196 } 197 } else { 198 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSTOFF), 199 file, refsec->c_name, ndx, strsec->c_name, 200 EC_XWORD(name), EC_XWORD(strn - 1)); 201 (void) fflush(stderr); 202 } 203 204 /* 205 * Return the empty string so that the calling function can 206 * continue it's output diagnostics. 207 */ 208 return (MSG_INTL(MSG_STR_UNKNOWN)); 209 } 210 return (strs + name); 211 } 212 213 /* 214 * Lookup a symbol and set Sym accordingly. 215 * 216 * Returns: 217 * 1 - symbol found 218 * 0 - symbol not found 219 */ 220 static int 221 symlookup(const char *name, Cache *cache, GElf_Word shnum, GElf_Sym *sym, 222 Cache *symtab, const char *file) 223 { 224 GElf_Shdr * shdr; 225 GElf_Word symn, cnt; 226 227 if (symtab == 0) 228 return (0); 229 230 shdr = &symtab->c_shdr; 231 /* 232 * Determine the symbol data and number. 233 */ 234 if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) { 235 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 236 file, symtab->c_name); 237 (void) fflush(stderr); 238 return (0); 239 } 240 /* LINTED */ 241 symn = (GElf_Word)(shdr->sh_size / shdr->sh_entsize); 242 243 /* 244 * Get the associated string table section. 245 */ 246 if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) { 247 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 248 file, symtab->c_name, EC_XWORD(shdr->sh_link)); 249 (void) fflush(stderr); 250 return (0); 251 } 252 253 /* 254 * Loop through the symbol table to find a match. 255 */ 256 for (cnt = 0; cnt < symn; cnt++) { 257 GElf_Sym tsym; 258 const char *sname; 259 260 if (gelf_getsym(symtab->c_data, cnt, &tsym) == NULL) { 261 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSYM), 262 file, symtab->c_name, elf_errmsg(0)); 263 (void) fflush(stderr); 264 return (0); 265 } 266 267 sname = string(symtab, cnt, &cache[shdr->sh_link], file, 268 tsym.st_name); 269 270 if (strcmp(name, sname) == 0) { 271 *sym = tsym; 272 return (1); 273 } 274 } 275 return (0); 276 } 277 278 /* 279 * The full usage message 280 */ 281 static void 282 detail_usage() 283 { 284 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL1)); 285 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL2)); 286 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL3)); 287 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL4)); 288 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL5)); 289 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL6)); 290 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL7)); 291 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL8)); 292 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL9)); 293 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL9_1)); 294 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL10)); 295 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL11)); 296 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL12)); 297 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL13)); 298 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL14)); 299 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL15)); 300 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL16)); 301 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL17)); 302 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL18)); 303 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL19)); 304 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL20)); 305 (void) fflush(stderr); 306 } 307 308 /* 309 * Print section headers. 310 */ 311 static void 312 sections(const char *file, Cache *cache, GElf_Word shnum, GElf_Ehdr *ehdr, 313 const char *name) 314 { 315 GElf_Word cnt; 316 Cache * _cache; 317 318 for (cnt = 1; cnt < shnum; cnt++) { 319 GElf_Shdr *shdr; 320 const char *sname; 321 322 _cache = &cache[cnt]; 323 sname = _cache->c_name; 324 if (name && strcmp(name, sname)) 325 continue; 326 327 /* 328 * Although numerous section header entries can be zero, it's 329 * usually a sign of trouble if the name or type are zero. 330 */ 331 shdr = &_cache->c_shdr; 332 if (shdr->sh_type == 0) { 333 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHTYPE), 334 file, sname, EC_XWORD(shdr->sh_type)); 335 (void) fflush(stderr); 336 } 337 if (shdr->sh_name == 0) { 338 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHNAME), 339 file, sname, EC_XWORD(shdr->sh_name)); 340 (void) fflush(stderr); 341 342 /* 343 * Use the empty string, rather than the fabricated 344 * name for the section output. 345 */ 346 sname = MSG_ORIG(MSG_STR_EMPTY); 347 } 348 349 dbg_print(MSG_ORIG(MSG_STR_EMPTY)); 350 /* LINTED */ 351 dbg_print(MSG_INTL(MSG_ELF_SHDR), (uint_t)cnt, sname); 352 Gelf_shdr_entry(ehdr->e_machine, shdr); 353 } 354 } 355 356 static void 357 unwind(Cache *cache, GElf_Word shnum, GElf_Ehdr *ehdr, const char *name, 358 const char *file, Elf *elf) 359 { 360 GElf_Word cnt; 361 GElf_Phdr unwind_phdr; 362 /* 363 * For the moment - UNWIND is only relevant for 364 * a AMD64 object 365 */ 366 if (ehdr->e_machine != EM_AMD64) 367 return; 368 369 unwind_phdr.p_type = PT_NULL; 370 371 for (cnt = 0; cnt < ehdr->e_phnum; cnt++) { 372 GElf_Phdr phdr; 373 374 if (gelf_getphdr(elf, cnt, &phdr) == NULL) { 375 failure(file, MSG_ORIG(MSG_ELF_GETPHDR)); 376 return; 377 } 378 379 if (phdr.p_type == PT_SUNW_UNWIND) { 380 unwind_phdr = phdr; 381 break; 382 } 383 } 384 385 386 for (cnt = 1; cnt < shnum; cnt++) { 387 Cache *_cache; 388 GElf_Shdr *shdr; 389 unsigned char *data; 390 size_t datasize; 391 uint64_t off, ndx; 392 393 394 _cache = &cache[cnt]; 395 shdr = &_cache->c_shdr; 396 /* 397 * XX64 - this is a strmcp() just to find the gcc 398 * produced sections. Soon gcc should be 399 * settng the section type - and we'll not need 400 * this strcmp(). 401 */ 402 if ((shdr->sh_type != SHT_AMD64_UNWIND) && 403 (strncmp(_cache->c_name, MSG_ORIG(MSG_SCN_FRM), 404 MSG_SCN_FRM_SIZE) != 0) && 405 (strncmp(_cache->c_name, MSG_ORIG(MSG_SCN_FRMHDR), 406 MSG_SCN_FRMHDR_SIZE) != 0)) 407 continue; 408 if (name && strcmp(name, _cache->c_name)) 409 continue; 410 411 dbg_print(MSG_ORIG(MSG_STR_EMPTY)); 412 dbg_print(MSG_INTL(MSG_ELF_SCN_UNWIND), _cache->c_name); 413 414 data = (unsigned char *)(_cache->c_data->d_buf); 415 datasize = _cache->c_data->d_size; 416 off = 0; 417 418 /* 419 * Is this a .eh_frame_hdr 420 */ 421 if (((unwind_phdr.p_type == PT_SUNW_UNWIND) && 422 (shdr->sh_addr == unwind_phdr.p_vaddr)) || 423 (strncmp(_cache->c_name, MSG_ORIG(MSG_SCN_FRMHDR), 424 MSG_SCN_FRMHDR_SIZE) == 0)) { 425 uint_t vers; 426 uint_t frame_ptr_enc; 427 uint64_t frame_ptr; 428 uint_t fde_cnt_enc; 429 uint64_t fde_cnt; 430 uint_t table_enc; 431 uint64_t tabndx; 432 433 dbg_print(MSG_ORIG(MSG_UNW_FRMHDR)); 434 ndx = 0; 435 436 vers = data[ndx++]; 437 frame_ptr_enc = data[ndx++]; 438 fde_cnt_enc = data[ndx++]; 439 table_enc = data[ndx++]; 440 441 dbg_print(MSG_ORIG(MSG_UNW_FRMVERS), vers); 442 443 frame_ptr = dwarf_ehe_extract(data, 444 &ndx, frame_ptr_enc, ehdr->e_ident, 445 shdr->sh_addr + ndx); 446 447 dbg_print(MSG_ORIG(MSG_UNW_FRPTRENC), 448 conv_dwarf_ehe_str(frame_ptr_enc), 449 frame_ptr); 450 451 fde_cnt = dwarf_ehe_extract(data, 452 &ndx, fde_cnt_enc, ehdr->e_ident, 453 shdr->sh_addr + ndx); 454 dbg_print(MSG_ORIG(MSG_UNW_FDCNENC), 455 conv_dwarf_ehe_str(fde_cnt_enc), 456 fde_cnt); 457 dbg_print(MSG_ORIG(MSG_UNW_TABENC), 458 conv_dwarf_ehe_str(table_enc)); 459 dbg_print(MSG_ORIG(MSG_UNW_BINSRTAB1)); 460 dbg_print(MSG_ORIG(MSG_UNW_BINSRTAB2)); 461 462 for (tabndx = 0; tabndx < fde_cnt; tabndx++) { 463 uint64_t init_loc; 464 uint64_t fde_loc; 465 init_loc = dwarf_ehe_extract(data, 466 &ndx, table_enc, ehdr->e_ident, 467 shdr->sh_addr); 468 fde_loc = dwarf_ehe_extract(data, 469 &ndx, table_enc, ehdr->e_ident, 470 shdr->sh_addr); 471 dbg_print(MSG_ORIG(MSG_UNW_BINSRTABENT), 472 init_loc, fde_loc); 473 } 474 continue; 475 } 476 477 /* 478 * Walk the Eh_frame's 479 */ 480 while (off < datasize) { 481 uint_t cieid, cielength, cieversion, 482 cieretaddr; 483 int cieRflag, cieLflag, 484 ciePflag, cieZflag; 485 uint_t length, id; 486 uint64_t ciecalign, ciedalign; 487 char *cieaugstr; 488 uint_t cieaugndx; 489 490 ndx = 0; 491 /* 492 * extract length in lsb format 493 */ 494 length = LSB32EXTRACT(data + off + ndx); 495 ndx += 4; 496 497 /* 498 * extract CIE id in lsb format 499 */ 500 id = LSB32EXTRACT(data + off + ndx); 501 ndx += 4; 502 503 /* 504 * A CIE record has a id of '0', otherwise 505 * this is a FDE entry and the 'id' is the 506 * CIE pointer. 507 */ 508 if (id == 0) { 509 uint64_t persVal; 510 cielength = length; 511 cieid = id; 512 513 cieLflag = 0; 514 ciePflag = 0; 515 cieRflag = 0; 516 cieZflag = 0; 517 518 dbg_print(MSG_ORIG(MSG_UNW_CIE), 519 shdr->sh_addr + off); 520 dbg_print(MSG_ORIG(MSG_UNW_CIELNGTH), 521 cielength, cieid); 522 cieversion = data[off + ndx]; 523 ndx += 1; 524 cieaugstr = (char *)(&data[off + ndx]); 525 ndx += strlen(cieaugstr) + 1; 526 dbg_print(MSG_ORIG(MSG_UNW_CIEVERS), 527 cieversion, cieaugstr); 528 ciecalign = uleb_extract(&data[off], &ndx); 529 ciedalign = sleb_extract(&data[off], &ndx); 530 cieretaddr = data[off + ndx]; 531 ndx += 1; 532 dbg_print(MSG_ORIG(MSG_UNW_CIECALGN), 533 ciecalign, ciedalign, cieretaddr); 534 535 if (cieaugstr[0]) 536 dbg_print(MSG_ORIG(MSG_UNW_CIEAUXVAL)); 537 for (cieaugndx = 0; cieaugstr[cieaugndx]; 538 cieaugndx++) { 539 uint_t val; 540 switch (cieaugstr[cieaugndx]) { 541 case 'z': 542 val = uleb_extract(&data[off], 543 &ndx); 544 dbg_print( 545 MSG_ORIG(MSG_UNW_CIEAUXSIZE), 546 val); 547 cieZflag = 1; 548 break; 549 case 'P': 550 ciePflag = data[off + ndx]; 551 ndx += 1; 552 553 persVal = dwarf_ehe_extract( 554 &data[off], 555 &ndx, ciePflag, ehdr->e_ident, 556 shdr->sh_addr + off + ndx); 557 dbg_print( 558 MSG_ORIG(MSG_UNW_CIEAUXPERS), 559 ciePflag, 560 conv_dwarf_ehe_str(ciePflag), 561 EC_XWORD(persVal)); 562 break; 563 case 'R': 564 val = data[off + ndx]; 565 ndx += 1; 566 dbg_print( 567 MSG_ORIG(MSG_UNW_CIEAUXCENC), 568 val, conv_dwarf_ehe_str(val)); 569 cieRflag = val; 570 break; 571 case 'L': 572 val = data[off + ndx]; 573 ndx += 1; 574 dbg_print( 575 MSG_ORIG(MSG_UNW_CIEAUXLSDA), 576 val, conv_dwarf_ehe_str(val)); 577 cieLflag = val; 578 break; 579 default: 580 dbg_print( 581 MSG_ORIG(MSG_UNW_CIEAUXUNEC), 582 cieaugstr[cieaugndx]); 583 break; 584 } 585 } 586 if ((cielength + 4) > ndx) { 587 uint_t cnt; 588 dbg_printf(MSG_ORIG(MSG_UNW_CIECFI)); 589 cnt = 0; 590 while (ndx < (cielength + 4)) { 591 if ((cnt++ % 8) == 0) { 592 dbg_printf( 593 MSG_ORIG(MSG_UNW_CIECFI1)); 594 } 595 dbg_printf( 596 MSG_ORIG(MSG_UNW_CIECFI2), 597 data[off + ndx++]); 598 } 599 dbg_print(MSG_ORIG(MSG_STR_EMPTY)); 600 } 601 off += cielength + 4; 602 } else { 603 uint_t fdelength = length; 604 int fdecieptr = id; 605 uint64_t fdeinitloc, fdeaddrrange; 606 607 dbg_print(MSG_ORIG(MSG_UNW_FDE), 608 shdr->sh_addr + off); 609 dbg_print(MSG_ORIG(MSG_UNW_FDELNGTH), 610 fdelength, fdecieptr); 611 fdeinitloc = dwarf_ehe_extract(&data[off], 612 &ndx, cieRflag, ehdr->e_ident, 613 shdr->sh_addr + off + ndx); 614 fdeaddrrange = dwarf_ehe_extract(&data[off], 615 &ndx, (cieRflag & ~DW_EH_PE_pcrel), 616 ehdr->e_ident, 617 shdr->sh_addr + off + ndx); 618 dbg_print(MSG_ORIG(MSG_UNW_FDEINITLOC), 619 fdeinitloc, fdeaddrrange); 620 if (cieaugstr[0]) 621 dbg_print(MSG_ORIG(MSG_UNW_FDEAUXVAL)); 622 if (cieZflag) { 623 uint64_t val; 624 val = uleb_extract(&data[off], &ndx); 625 dbg_print( 626 MSG_ORIG(MSG_UNW_FDEAUXSIZE), val); 627 if (val & cieLflag) { 628 fdeinitloc = dwarf_ehe_extract( 629 &data[off], &ndx, cieLflag, 630 ehdr->e_ident, 631 shdr->sh_addr + off + ndx); 632 dbg_print( 633 MSG_ORIG(MSG_UNW_FDEAUXLSDA), 634 val); 635 } 636 } 637 if ((fdelength + 4) > ndx) { 638 uint_t cnt; 639 dbg_printf(MSG_ORIG(MSG_UNW_FDECFI)); 640 cnt = 0; 641 while (ndx < (fdelength + 4)) { 642 if ((cnt++ % 8) == 0) { 643 dbg_printf( 644 MSG_ORIG(MSG_UNW_FDECFI1)); 645 } 646 dbg_printf( 647 MSG_ORIG(MSG_UNW_FDECFI2), 648 data[off + ndx++]); 649 } 650 dbg_print(MSG_ORIG(MSG_STR_EMPTY)); 651 } 652 653 off += fdelength + 4; 654 } 655 } 656 } 657 } 658 659 /* 660 * Print the hardware/software capabilities. For executables and shared objects 661 * this should be accompanied with a program header. 662 */ 663 static void 664 cap(const char *file, Cache *cache, GElf_Word shnum, GElf_Ehdr *ehdr, 665 Elf *elf) 666 { 667 GElf_Word cnt; 668 GElf_Shdr * cshdr = 0; 669 Cache * ccache; 670 Elf64_Off cphdr_off = 0; 671 Elf64_Xword cphdr_sz; 672 673 /* 674 * Determine if a hardware/software capabilities header exists. 675 */ 676 for (cnt = 0; cnt < ehdr->e_phnum; cnt++) { 677 GElf_Phdr phdr; 678 679 if (gelf_getphdr(elf, cnt, &phdr) == NULL) { 680 failure(file, MSG_ORIG(MSG_ELF_GETPHDR)); 681 return; 682 } 683 684 if (phdr.p_type == PT_SUNWCAP) { 685 cphdr_off = phdr.p_offset; 686 cphdr_sz = phdr.p_filesz; 687 break; 688 } 689 } 690 691 /* 692 * Determine if a hardware/software capabilities section exists. 693 */ 694 for (cnt = 1; cnt < shnum; cnt++) { 695 Cache * _cache; 696 GElf_Shdr *shdr; 697 698 _cache = &cache[cnt]; 699 shdr = &_cache->c_shdr; 700 701 if (shdr->sh_type != SHT_SUNW_cap) 702 continue; 703 704 if (cphdr_off && ((cphdr_off < shdr->sh_offset) || 705 (cphdr_off + cphdr_sz) > (shdr->sh_offset + shdr->sh_size))) 706 continue; 707 708 ccache = _cache; 709 cshdr = shdr; 710 break; 711 } 712 713 if ((cshdr == 0) && (cphdr_off == 0)) 714 return; 715 716 /* 717 * Print the hardware/software capabilities section. 718 */ 719 if (cshdr) { 720 GElf_Word ndx, capn; 721 722 dbg_print(MSG_ORIG(MSG_STR_EMPTY)); 723 dbg_print(MSG_INTL(MSG_ELF_SCN_CAP), ccache->c_name); 724 725 Gelf_cap_title(); 726 727 /* LINTED */ 728 capn = (GElf_Word)(cshdr->sh_size / cshdr->sh_entsize); 729 730 /* LINTED */ 731 for (ndx = 0; ndx < capn; ndx++) { 732 GElf_Cap cap; 733 734 if (gelf_getcap(ccache->c_data, ndx, &cap) == NULL) { 735 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADCAP), 736 file, ccache->c_name, elf_errmsg(0)); 737 (void) fflush(stderr); 738 return; 739 } 740 if (cap.c_tag != CA_SUNW_NULL) 741 Gelf_cap_print(&cap, ndx, ehdr->e_machine); 742 } 743 } else 744 (void) fprintf(stderr, MSG_INTL(MSG_WARN_INVCAP1), file); 745 746 /* 747 * If this object is an executable or shared object, then the 748 * hardware/software capabilities section should have an accompanying 749 * program header. 750 */ 751 if (cshdr && ((ehdr->e_type == ET_EXEC) || (ehdr->e_type == ET_DYN))) { 752 if (cphdr_off == 0) 753 (void) fprintf(stderr, MSG_INTL(MSG_WARN_INVCAP2), 754 file, ccache->c_name); 755 else if ((cphdr_off != cshdr->sh_offset) || 756 (cphdr_sz != cshdr->sh_size)) 757 (void) fprintf(stderr, MSG_INTL(MSG_WARN_INVCAP3), 758 file, ccache->c_name); 759 } 760 } 761 762 /* 763 * Print the interpretor. 764 */ 765 static void 766 interp(const char *file, Cache *cache, GElf_Word shnum, GElf_Ehdr *ehdr, 767 Elf *elf) 768 { 769 GElf_Word cnt; 770 GElf_Shdr * ishdr = 0; 771 Cache * icache; 772 Elf64_Off iphdr_off = 0; 773 Elf64_Xword iphdr_sz; 774 775 /* 776 * Determine if an interp header exists. 777 */ 778 for (cnt = 0; cnt < ehdr->e_phnum; cnt++) { 779 GElf_Phdr phdr; 780 781 if (gelf_getphdr(elf, cnt, &phdr) == NULL) { 782 failure(file, MSG_ORIG(MSG_ELF_GETPHDR)); 783 return; 784 } 785 786 if (phdr.p_type == PT_INTERP) { 787 iphdr_off = phdr.p_offset; 788 iphdr_sz = phdr.p_filesz; 789 break; 790 } 791 } 792 793 if (iphdr_off == 0) 794 return; 795 796 /* 797 * Determine if an interp section exists. 798 */ 799 for (cnt = 1; cnt < shnum; cnt++) { 800 Cache * _cache; 801 GElf_Shdr *shdr; 802 803 _cache = &cache[cnt]; 804 shdr = &_cache->c_shdr; 805 806 /* 807 * Scan sections to find a section which contains the PT_INTERP 808 * string. The target section can't be in a NOBITS section. 809 */ 810 if ((shdr->sh_type == SHT_NOBITS) || 811 (iphdr_off < shdr->sh_offset) || 812 (iphdr_off + iphdr_sz) > (shdr->sh_offset + shdr->sh_size)) 813 continue; 814 815 icache = _cache; 816 ishdr = shdr; 817 break; 818 } 819 820 /* 821 * Print the interpreter string based on the offset defined in the 822 * program header, as this is the offset used by the kernel. 823 */ 824 if (ishdr) { 825 dbg_print(MSG_ORIG(MSG_STR_EMPTY)); 826 dbg_print(MSG_INTL(MSG_ELF_SCN_INTERP), icache->c_name); 827 dbg_print(MSG_ORIG(MSG_FMT_INDENT), 828 (char *)icache->c_data->d_buf + 829 (iphdr_off - ishdr->sh_offset)); 830 } else 831 (void) fprintf(stderr, MSG_INTL(MSG_WARN_INVINTERP1), file); 832 833 /* 834 * If there are any inconsistences between the program header and 835 * section information, flag them. 836 */ 837 if (ishdr && ((iphdr_off != ishdr->sh_offset) || 838 (iphdr_sz != ishdr->sh_size))) { 839 (void) fprintf(stderr, MSG_INTL(MSG_WARN_INVINTERP2), file, 840 icache->c_name); 841 (void) fflush(stderr); 842 } 843 } 844 845 /* 846 * Print the syminfo section. 847 */ 848 static void 849 syminfo(Cache *cache, GElf_Word shnum, const char *file) 850 { 851 GElf_Shdr *shdr; 852 Elf_Data *dsyms, *ddyn; 853 GElf_Word symn, cnt, ndx; 854 Cache *syminfo = 0; 855 char *sname; 856 857 for (cnt = 1; cnt < shnum; cnt++) { 858 if (cache[cnt].c_shdr.sh_type == SHT_SUNW_syminfo) { 859 syminfo = &cache[cnt]; 860 break; 861 } 862 } 863 if (syminfo == 0) 864 return; 865 866 shdr = &syminfo->c_shdr; 867 /* 868 * Determine the symbol info data and number. 869 */ 870 if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) { 871 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 872 file, syminfo->c_name); 873 (void) fflush(stderr); 874 return; 875 } 876 /* LINTED */ 877 symn = (GElf_Word)(shdr->sh_size / shdr->sh_entsize); 878 879 /* 880 * Get the data buffer of the associated dynamic section. 881 */ 882 if ((shdr->sh_info == 0) || (shdr->sh_info >= shnum)) { 883 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHINFO), 884 file, syminfo->c_name, EC_XWORD(shdr->sh_info)); 885 (void) fflush(stderr); 886 return; 887 } 888 ddyn = cache[shdr->sh_info].c_data; 889 if (ddyn->d_buf == 0) { 890 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 891 file, cache[shdr->sh_info].c_name); 892 (void) fflush(stderr); 893 return; 894 } 895 896 /* 897 * Get the data buffer of the associated symbol table. 898 */ 899 if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) { 900 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 901 file, syminfo->c_name, EC_XWORD(shdr->sh_link)); 902 (void) fflush(stderr); 903 return; 904 } 905 dsyms = cache[shdr->sh_link].c_data; 906 if (dsyms->d_buf == 0) { 907 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 908 file, cache[shdr->sh_link].c_name); 909 (void) fflush(stderr); 910 return; 911 } 912 913 sname = cache[shdr->sh_link].c_name; 914 shdr = &cache[shdr->sh_link].c_shdr; 915 /* 916 * Get the associated string table section. 917 */ 918 if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) { 919 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 920 file, sname, EC_XWORD(shdr->sh_link)); 921 (void) fflush(stderr); 922 return; 923 } 924 925 dbg_print(MSG_ORIG(MSG_STR_EMPTY)); 926 dbg_print(MSG_INTL(MSG_ELF_SCN_SYMINFO), syminfo->c_name); 927 Gelf_syminfo_title(); 928 929 for (ndx = 1; ndx < symn; ndx++) { 930 GElf_Syminfo gsip; 931 GElf_Sym gsym; 932 GElf_Dyn gdyn; 933 const char *needed, *sname; 934 935 if (gelf_getsyminfo(syminfo->c_data, ndx, &gsip) == 0) { 936 (void) fprintf(stderr, MSG_INTL(MSG_ERR_SIBADCOUNT), 937 file, syminfo->c_name, ndx); 938 (void) fflush(stderr); 939 return; 940 } 941 if ((gsip.si_flags == 0) && (gsip.si_boundto == 0)) 942 continue; 943 944 if (gelf_getsym(dsyms, ndx, &gsym) == 0) { 945 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSYM), 946 file, syminfo->c_name, elf_errmsg(0)); 947 (void) fflush(stderr); 948 return; 949 } 950 951 sname = string(syminfo, cnt, &cache[shdr->sh_link], file, 952 gsym.st_name); 953 needed = 0; 954 955 if (gsip.si_boundto < SYMINFO_BT_LOWRESERVE) { 956 if (gelf_getdyn(ddyn, gsip.si_boundto, &gdyn) == 0) { 957 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADDYN), 958 file, syminfo->c_name, gsip.si_boundto); 959 (void) fflush(stderr); 960 return; 961 } 962 needed = string(syminfo, gsip.si_boundto, 963 &cache[shdr->sh_link], file, gdyn.d_un.d_val); 964 } 965 966 Gelf_syminfo_entry(ndx, &gsip, sname, needed); 967 } 968 } 969 970 /* 971 * Print version definition section entries. 972 */ 973 static void 974 version_def(GElf_Verdef *vdf, GElf_Word shnum, Cache *vcache, Cache *scache, 975 const char *file) 976 { 977 GElf_Word cnt; 978 char index[MAXNDXSIZE]; 979 980 Gelf_ver_def_title(); 981 982 for (cnt = 1; cnt <= shnum; cnt++, 983 vdf = (GElf_Verdef *)((uintptr_t)vdf + vdf->vd_next)) { 984 985 GElf_Half vcnt = vdf->vd_cnt - 1; 986 GElf_Half ndx = vdf->vd_ndx; 987 GElf_Verdaux *vdap = (GElf_Verdaux *) 988 ((uintptr_t)vdf + vdf->vd_aux); 989 const char *name, *dep; 990 991 /* 992 * Obtain the name and first dependency (if any). 993 */ 994 name = string(vcache, cnt, scache, file, vdap->vda_name); 995 vdap = (GElf_Verdaux *)((uintptr_t)vdap + vdap->vda_next); 996 if (vcnt) 997 dep = string(vcache, cnt, scache, file, vdap->vda_name); 998 else 999 dep = MSG_ORIG(MSG_STR_EMPTY); 1000 1001 (void) snprintf(index, MAXNDXSIZE, MSG_ORIG(MSG_FMT_INDEX), 1002 EC_XWORD(ndx)); 1003 Gelf_ver_line_1(index, name, dep, 1004 conv_verflg_str(vdf->vd_flags)); 1005 1006 /* 1007 * Print any additional dependencies. 1008 */ 1009 if (vcnt) { 1010 vdap = (GElf_Verdaux *)((uintptr_t)vdap + 1011 vdap->vda_next); 1012 for (vcnt--; vcnt; vcnt--, 1013 vdap = (GElf_Verdaux *)((uintptr_t)vdap + 1014 vdap->vda_next)) { 1015 dep = string(vcache, cnt, scache, file, 1016 vdap->vda_name); 1017 Gelf_ver_line_2(MSG_ORIG(MSG_STR_EMPTY), dep); 1018 } 1019 } 1020 } 1021 } 1022 1023 /* 1024 * Print a version needed section entries. 1025 */ 1026 static void 1027 version_need(GElf_Verneed *vnd, GElf_Word shnum, Cache *vcache, Cache *scache, 1028 const char *file) 1029 { 1030 GElf_Word cnt; 1031 1032 Gelf_ver_need_title(); 1033 1034 for (cnt = 1; cnt <= shnum; cnt++, 1035 vnd = (GElf_Verneed *)((uintptr_t)vnd + vnd->vn_next)) { 1036 1037 GElf_Half vcnt = vnd->vn_cnt; 1038 GElf_Vernaux *vnap = (GElf_Vernaux *)((uintptr_t)vnd + 1039 vnd->vn_aux); 1040 const char *name, *dep; 1041 1042 /* 1043 * Obtain the name of the needed file and the version name 1044 * within it that we're dependent on. Note that the count 1045 * should be at least one, otherwise this is a pretty bogus 1046 * entry. 1047 */ 1048 name = string(vcache, cnt, scache, file, vnd->vn_file); 1049 if (vcnt) 1050 dep = string(vcache, cnt, scache, file, vnap->vna_name); 1051 else 1052 dep = MSG_INTL(MSG_STR_NULL); 1053 1054 Gelf_ver_line_1(MSG_ORIG(MSG_STR_EMPTY), name, dep, 1055 conv_verflg_str(vnap->vna_flags)); 1056 1057 /* 1058 * Print any additional version dependencies. 1059 */ 1060 if (vcnt) { 1061 vnap = (GElf_Vernaux *)((uintptr_t)vnap + 1062 vnap->vna_next); 1063 for (vcnt--; vcnt; vcnt--, 1064 vnap = (GElf_Vernaux *)((uintptr_t)vnap + 1065 vnap->vna_next)) { 1066 dep = string(vcache, cnt, scache, file, 1067 vnap->vna_name); 1068 Gelf_ver_line_3(MSG_ORIG(MSG_STR_EMPTY), dep, 1069 conv_verflg_str(vnap->vna_flags)); 1070 } 1071 } 1072 } 1073 } 1074 1075 /* 1076 * Search for any verion sections - the Versym output is possibly 1077 * used by the symbols() printing. If VERSYM is specified - then 1078 * display the version information. 1079 */ 1080 static Cache * 1081 versions(Cache *cache, GElf_Word shnum, const char *file, uint32_t flags) 1082 { 1083 GElf_Word cnt; 1084 Cache *versymcache = 0; 1085 1086 for (cnt = 1; cnt < shnum; cnt++) { 1087 void * ver; 1088 uint_t num; 1089 Cache * _cache = &cache[cnt]; 1090 GElf_Shdr * shdr = &_cache->c_shdr; 1091 1092 /* 1093 * If this is the version symbol table simply record its 1094 * data address for possible use in later symbol processing. 1095 */ 1096 if (shdr->sh_type == SHT_SUNW_versym) { 1097 versymcache = _cache; 1098 continue; 1099 } 1100 1101 if ((flags & FLG_VERSIONS) == 0) 1102 continue; 1103 1104 if ((shdr->sh_type != SHT_SUNW_verdef) && 1105 (shdr->sh_type != SHT_SUNW_verneed)) 1106 continue; 1107 1108 /* 1109 * Determine the version section data and number. 1110 */ 1111 if ((ver = (void *)_cache->c_data->d_buf) == 0) { 1112 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 1113 file, _cache->c_name); 1114 (void) fflush(stderr); 1115 continue; 1116 } 1117 if ((num = shdr->sh_info) == 0) { 1118 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHINFO), 1119 file, _cache->c_name, EC_XWORD(shdr->sh_info)); 1120 (void) fflush(stderr); 1121 continue; 1122 } 1123 1124 /* 1125 * Get the data buffer for the associated string table. 1126 */ 1127 if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) { 1128 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 1129 file, _cache->c_name, EC_XWORD(shdr->sh_link)); 1130 (void) fflush(stderr); 1131 continue; 1132 } 1133 1134 dbg_print(MSG_ORIG(MSG_STR_EMPTY)); 1135 if (shdr->sh_type == SHT_SUNW_verdef) { 1136 dbg_print(MSG_INTL(MSG_ELF_SCN_VERDEF), 1137 _cache->c_name); 1138 version_def((GElf_Verdef *)ver, num, _cache, 1139 &cache[shdr->sh_link], file); 1140 } else if (shdr->sh_type == SHT_SUNW_verneed) { 1141 dbg_print(MSG_INTL(MSG_ELF_SCN_VERNEED), 1142 _cache->c_name); 1143 version_need((GElf_Verneed *)ver, num, _cache, 1144 &cache[shdr->sh_link], file); 1145 } 1146 } 1147 return (versymcache); 1148 } 1149 1150 /* 1151 * Search for and process any symbol tables. 1152 */ 1153 static void 1154 symbols(Cache *cache, GElf_Word shnum, GElf_Ehdr *ehdr, const char *name, 1155 Cache *versymcache, const char *file) 1156 { 1157 GElf_Word cnt; 1158 char is_core = (ehdr->e_type == ET_CORE); 1159 1160 for (cnt = 1; cnt < shnum; cnt++) { 1161 GElf_Sym sym; 1162 GElf_Word symn, _cnt; 1163 GElf_Versym *versym; 1164 Cache *_cache = &cache[cnt]; 1165 GElf_Shdr *shdr = &_cache->c_shdr; 1166 Word *symshndx; 1167 uint_t nosymshndx; 1168 uint_t nosyminshndx; 1169 1170 if ((shdr->sh_type != SHT_SYMTAB) && 1171 (shdr->sh_type != SHT_DYNSYM)) 1172 continue; 1173 if (name && strcmp(name, _cache->c_name)) 1174 continue; 1175 1176 /* 1177 * Determine the symbol data and number. 1178 */ 1179 if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) { 1180 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 1181 file, _cache->c_name); 1182 (void) fflush(stderr); 1183 continue; 1184 } 1185 /* LINTED */ 1186 symn = (GElf_Word)(shdr->sh_size / shdr->sh_entsize); 1187 1188 /* 1189 * Get the associated string table section. 1190 */ 1191 if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) { 1192 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 1193 file, _cache->c_name, EC_XWORD(shdr->sh_link)); 1194 (void) fflush(stderr); 1195 continue; 1196 } 1197 1198 /* 1199 * Determine if there is a associated Versym section 1200 * with this Symbol Table. 1201 */ 1202 if (versymcache && (versymcache->c_shdr.sh_link == cnt)) 1203 versym = versymcache->c_data->d_buf; 1204 else 1205 versym = 0; 1206 1207 /* 1208 * Loop through the symbol tables entries. 1209 */ 1210 dbg_print(MSG_ORIG(MSG_STR_EMPTY)); 1211 dbg_print(MSG_INTL(MSG_ELF_SCN_SYMTAB), _cache->c_name); 1212 Gelf_sym_table_title(ehdr, MSG_INTL(MSG_STR_INDEX), 1213 MSG_INTL(MSG_STR_NAME)); 1214 1215 symshndx = 0; 1216 nosymshndx = 0; 1217 nosyminshndx = 0; 1218 for (_cnt = 0; _cnt < symn; _cnt++) { 1219 char index[MAXNDXSIZE]; 1220 char *sec; 1221 const char *sname; 1222 int verndx; 1223 uchar_t type; 1224 GElf_Shdr *tshdr; 1225 Word shndx; 1226 1227 if (gelf_getsym(_cache->c_data, _cnt, &sym) == NULL) { 1228 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSYM), 1229 file, _cache->c_name, elf_errmsg(0)); 1230 (void) fflush(stderr); 1231 break; 1232 } 1233 1234 /* 1235 * If we are using extended symbol indexes, find the 1236 * corresponding SHN_SYMTAB_SHNDX table. 1237 */ 1238 if ((sym.st_shndx == SHN_XINDEX) && 1239 (symshndx == 0) && (nosymshndx == 0)) { 1240 Word __cnt; 1241 1242 for (__cnt = 1; __cnt < shnum; __cnt++) { 1243 Cache *_cache = &cache[__cnt]; 1244 GElf_Shdr *shdr = &_cache->c_shdr; 1245 1246 if ((shdr->sh_type != 1247 SHT_SYMTAB_SHNDX) || 1248 (shdr->sh_link != cnt)) 1249 continue; 1250 if (shdr->sh_entsize) 1251 /* LINTED */ 1252 nosyminshndx = (uint_t) 1253 shdr->sh_size/shdr->sh_entsize; 1254 if (nosyminshndx == 0) 1255 continue; 1256 symshndx = _cache->c_data->d_buf; 1257 break; 1258 } 1259 if (symshndx == 0) 1260 nosymshndx = 1; 1261 } 1262 1263 /* LINTED */ 1264 sname = string(_cache, _cnt, &cache[shdr->sh_link], 1265 file, sym.st_name); 1266 1267 tshdr = 0; 1268 sec = NULL; 1269 1270 if (is_core) 1271 sec = (char *)MSG_INTL(MSG_STR_UNKNOWN); 1272 else if ((sym.st_shndx < SHN_LORESERVE) && 1273 (sym.st_shndx < shnum)) { 1274 shndx = sym.st_shndx; 1275 tshdr = &(cache[shndx].c_shdr); 1276 sec = cache[shndx].c_name; 1277 } else if (sym.st_shndx == SHN_XINDEX) { 1278 if (symshndx) { 1279 Word _symshndx; 1280 1281 if (_cnt > nosyminshndx) { 1282 (void) fprintf(stderr, 1283 MSG_INTL(MSG_ERR_BADSYMXINDEX1), 1284 file, _cache->c_name, 1285 EC_WORD(_cnt)); 1286 (void) fflush(stderr); 1287 } else if ((_symshndx = 1288 symshndx[_cnt]) > shnum) { 1289 (void) fprintf(stderr, 1290 MSG_INTL(MSG_ERR_BADSYMXINDEX2), 1291 file, _cache->c_name, 1292 EC_WORD(_cnt), 1293 EC_WORD(_symshndx)); 1294 (void) fflush(stderr); 1295 } else { 1296 shndx = _symshndx; 1297 tshdr = &(cache[shndx].c_shdr); 1298 sec = cache[shndx].c_name; 1299 } 1300 } else { 1301 (void) fprintf(stderr, 1302 MSG_INTL(MSG_ERR_BADSYMXINDEX3), 1303 file, _cache->c_name, 1304 EC_WORD(_cnt)); 1305 (void) fflush(stderr); 1306 } 1307 } else if ((sym.st_shndx < SHN_LORESERVE) && 1308 (sym.st_shndx >= shnum)) { 1309 (void) fprintf(stderr, 1310 MSG_INTL(MSG_ERR_BADSYM5), 1311 file, _cache->c_name, 1312 sname, sym.st_shndx); 1313 (void) fflush(stderr); 1314 } 1315 1316 /* 1317 * If versioning is available display the 1318 * version index. 1319 */ 1320 if (versym) 1321 verndx = (int)versym[_cnt]; 1322 else 1323 verndx = 0; 1324 1325 /* 1326 * Error checking for TLS. 1327 */ 1328 type = ELF_ST_TYPE(sym.st_info); 1329 if (type == STT_TLS) { 1330 if (tshdr && 1331 (sym.st_shndx != SHN_UNDEF) && 1332 ((tshdr->sh_flags & SHF_TLS) == 0)) { 1333 (void) fprintf(stderr, 1334 MSG_INTL(MSG_ERR_BADSYM3), file, 1335 _cache->c_name, sname); 1336 (void) fflush(stderr); 1337 } 1338 } else if ((type != STT_SECTION) && sym.st_size && 1339 tshdr && (tshdr->sh_flags & SHF_TLS)) { 1340 (void) fprintf(stderr, 1341 MSG_INTL(MSG_ERR_BADSYM4), file, 1342 _cache->c_name, sname); 1343 (void) fflush(stderr); 1344 } 1345 1346 /* 1347 * If a symbol has size, then make sure the section it 1348 * references is appropriate. Note, UNDEF symbols that 1349 * have a size, have been known to exist - ignore them. 1350 */ 1351 if (sym.st_size && shndx && tshdr && 1352 (tshdr->sh_size < sym.st_size)) { 1353 (void) fprintf(stderr, 1354 MSG_INTL(MSG_ERR_BADSYM6), file, 1355 _cache->c_name, sname, EC_WORD(shndx), 1356 EC_XWORD(tshdr->sh_size), 1357 EC_XWORD(sym.st_size)); 1358 (void) fflush(stderr); 1359 } 1360 1361 (void) snprintf(index, MAXNDXSIZE, 1362 MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(_cnt)); 1363 1364 Gelf_sym_table_entry(index, ehdr, &sym, verndx, sec, 1365 sname); 1366 } 1367 } 1368 } 1369 1370 /* 1371 * Search for and process any relocation sections. 1372 */ 1373 static void 1374 reloc(Cache *cache, GElf_Word shnum, GElf_Ehdr *ehdr, const char *name, 1375 const char *file, uint32_t flags) 1376 { 1377 GElf_Word cnt; 1378 1379 for (cnt = 1; cnt < shnum; cnt++) { 1380 Word type; 1381 ulong_t numrels, entsize; 1382 int ndx; 1383 Elf_Data *dsyms; 1384 Cache *_cache = &cache[cnt]; 1385 GElf_Shdr *shdr = &_cache->c_shdr; 1386 char *sname; 1387 1388 if (((type = shdr->sh_type) != SHT_RELA) && 1389 (type != SHT_REL)) 1390 continue; 1391 if (name && strcmp(name, _cache->c_name)) 1392 continue; 1393 1394 /* 1395 * Decide entry size 1396 */ 1397 if (((entsize = shdr->sh_entsize) == 0) || 1398 (entsize > shdr->sh_size)) { 1399 if (type == SHT_RELA) 1400 entsize = sizeof (GElf_Rela); 1401 else 1402 entsize = sizeof (GElf_Rel); 1403 } 1404 1405 /* 1406 * Determine the number of relocations available. 1407 */ 1408 if (shdr->sh_size == 0) { 1409 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 1410 file, _cache->c_name); 1411 (void) fflush(stderr); 1412 continue; 1413 } 1414 numrels = shdr->sh_size / entsize; 1415 1416 /* 1417 * Get the data buffer for the associated symbol table. Note 1418 * that we've been known to create static binaries containing 1419 * relocations against weak symbols, if these get stripped the 1420 * relocation records can't make symbolic references. 1421 */ 1422 if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) { 1423 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 1424 file, _cache->c_name, EC_XWORD(shdr->sh_link)); 1425 (void) fflush(stderr); 1426 continue; 1427 } 1428 dsyms = cache[shdr->sh_link].c_data; 1429 if (dsyms->d_buf == 0) { 1430 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 1431 file, cache[shdr->sh_link].c_name); 1432 (void) fflush(stderr); 1433 continue; 1434 } 1435 1436 sname = cache[shdr->sh_link].c_name; 1437 shdr = &cache[shdr->sh_link].c_shdr; 1438 /* 1439 * Get the associated string table section. 1440 */ 1441 if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) { 1442 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 1443 file, sname, EC_XWORD(shdr->sh_link)); 1444 (void) fflush(stderr); 1445 continue; 1446 } 1447 1448 /* 1449 * Loop through the relocation entries. 1450 */ 1451 dbg_print(MSG_ORIG(MSG_STR_EMPTY)); 1452 dbg_print(MSG_INTL(MSG_ELF_SCN_RELOC), _cache->c_name); 1453 if (type == SHT_RELA) { 1454 if (flags & FLG_LONGNAME) 1455 dbg_print(MSG_INTL(MSG_ELF_L_RELOC_RELA)); 1456 else 1457 dbg_print(MSG_INTL(MSG_ELF_RELOC_RELA)); 1458 } else { 1459 if (flags & FLG_LONGNAME) 1460 dbg_print(MSG_INTL(MSG_ELF_L_RELOC_REL)); 1461 else 1462 dbg_print(MSG_INTL(MSG_ELF_RELOC_REL)); 1463 } 1464 1465 /* LINTED */ 1466 for (ndx = 0; ndx < numrels; ndx++) { 1467 char section[BUFSIZ]; 1468 const char *_name; 1469 GElf_Word sndx; 1470 ulong_t r_type; 1471 GElf_Sym _sym; 1472 GElf_Rela rela; 1473 1474 /* 1475 * Determine the symbol with which this relocation is 1476 * associated. If the symbol represents a section 1477 * offset construct an appropriate string. 1478 */ 1479 if (type == SHT_RELA) { 1480 (void) gelf_getrela(_cache->c_data, ndx, 1481 &rela); 1482 } else { 1483 (void) gelf_getrel(_cache->c_data, ndx, 1484 (GElf_Rel*)&rela); 1485 } 1486 /* LINTED */ 1487 sndx = (GElf_Word)GELF_R_SYM(rela.r_info); 1488 r_type = GELF_R_TYPE(rela.r_info); 1489 1490 /* LINTED */ 1491 if (gelf_getsym(dsyms, (int)sndx, &_sym) == NULL) { 1492 (void) fprintf(stderr, 1493 MSG_INTL(MSG_ERR_RELBADSYMNDX), 1494 file, elf_errmsg(0)); 1495 (void) fflush(stderr); 1496 _name = MSG_INTL(MSG_STR_UNKNOWN); 1497 } else { 1498 if ((GELF_ST_TYPE(_sym.st_info) == 1499 STT_SECTION) && (_sym.st_name == 0)) { 1500 if (flags & FLG_LONGNAME) 1501 (void) snprintf(section, BUFSIZ, 1502 MSG_INTL(MSG_STR_L_SECTION), 1503 cache[_sym.st_shndx].c_name); 1504 else 1505 (void) snprintf(section, BUFSIZ, 1506 MSG_INTL(MSG_STR_SECTION), 1507 cache[_sym.st_shndx].c_name); 1508 _name = (const char *)section; 1509 } else { 1510 /* LINTED */ 1511 _name = string(_cache, 1512 sndx, &cache[shdr->sh_link], 1513 file, _sym.st_name); 1514 } 1515 } 1516 1517 if ((sndx == 0) && ((IAM_SPARC(ehdr->e_machine) && 1518 ((r_type != R_SPARC_NONE) && 1519 (r_type != R_SPARC_REGISTER) && 1520 (r_type != R_SPARC_RELATIVE))) || 1521 ((IAM_INTEL(ehdr->e_machine) && 1522 ((r_type != R_386_NONE) && 1523 (r_type != R_386_RELATIVE)))))) { 1524 (void) fprintf(stderr, 1525 MSG_INTL(MSG_ERR_BADREL1), file, 1526 conv_reloc_type_str(ehdr->e_machine, 1527 /* LINTED */ 1528 (uint_t)r_type)); 1529 (void) fflush(stderr); 1530 } 1531 1532 Gelf_reloc_entry(MSG_ORIG(MSG_STR_EMPTY), 1533 ehdr->e_machine, type, (void *)&rela, 1534 _cache->c_name, _name); 1535 } 1536 } 1537 } 1538 1539 /* 1540 * Search for and process a .dynamic section. 1541 */ 1542 static void 1543 dynamic(Cache *cache, GElf_Word shnum, GElf_Ehdr *ehdr, const char *file) 1544 { 1545 GElf_Word cnt; 1546 1547 for (cnt = 1; cnt < shnum; cnt++) { 1548 GElf_Dyn dyn; 1549 ulong_t numdyn; 1550 int ndx; 1551 Cache * _cache = &cache[cnt]; 1552 GElf_Shdr * shdr = &_cache->c_shdr; 1553 1554 if (shdr->sh_type != SHT_DYNAMIC) 1555 continue; 1556 1557 /* 1558 * Get the associated string table section. 1559 */ 1560 if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) { 1561 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 1562 file, _cache->c_name, EC_XWORD(shdr->sh_link)); 1563 (void) fflush(stderr); 1564 continue; 1565 } 1566 numdyn = shdr->sh_size / shdr->sh_entsize; 1567 1568 dbg_print(MSG_ORIG(MSG_STR_EMPTY)); 1569 dbg_print(MSG_INTL(MSG_ELF_SCN_DYNAMIC), _cache->c_name); 1570 1571 Gelf_dyn_title(); 1572 1573 /* LINTED */ 1574 for (ndx = 0; ndx < numdyn; ++ndx) { 1575 const char *name; 1576 1577 (void) gelf_getdyn(_cache->c_data, ndx, &dyn); 1578 if (dyn.d_tag == DT_NULL) 1579 break; 1580 1581 /* 1582 * Print the information numerically, and if possible 1583 * as a string. 1584 */ 1585 if ((dyn.d_tag == DT_NEEDED) || 1586 (dyn.d_tag == DT_SONAME) || 1587 (dyn.d_tag == DT_FILTER) || 1588 (dyn.d_tag == DT_AUXILIARY) || 1589 (dyn.d_tag == DT_CONFIG) || 1590 (dyn.d_tag == DT_RPATH) || 1591 (dyn.d_tag == DT_RUNPATH) || 1592 (dyn.d_tag == DT_USED) || 1593 (dyn.d_tag == DT_DEPAUDIT) || 1594 (dyn.d_tag == DT_AUDIT) || 1595 (dyn.d_tag == DT_SUNW_AUXILIARY) || 1596 (dyn.d_tag == DT_SUNW_FILTER)) 1597 name = string(_cache, ndx, 1598 &cache[shdr->sh_link], file, 1599 dyn.d_un.d_ptr); 1600 else if (dyn.d_tag == DT_FLAGS) 1601 /* LINTED */ 1602 name = conv_dynflag_str((Word)dyn.d_un.d_val); 1603 else if (dyn.d_tag == DT_FLAGS_1) 1604 /* LINTED */ 1605 name = conv_dynflag_1_str((Word)dyn.d_un.d_val); 1606 else if (dyn.d_tag == DT_POSFLAG_1) 1607 /* LINTED */ 1608 name = conv_dynposflag_1_str((Word)dyn.d_un.d_val); 1609 else if (dyn.d_tag == DT_FEATURE_1) 1610 /* LINTED */ 1611 name = conv_dynfeature_1_str((Word)dyn.d_un.d_val); 1612 else if (dyn.d_tag == DT_DEPRECATED_SPARC_REGISTER) 1613 name = MSG_INTL(MSG_STR_DEPRECATED); 1614 else 1615 name = MSG_ORIG(MSG_STR_EMPTY); 1616 1617 Gelf_dyn_print(&dyn, ndx, name, ehdr->e_machine); 1618 } 1619 } 1620 } 1621 1622 /* 1623 * Search for and process a MOVE section. 1624 */ 1625 static void 1626 move(Cache *cache, GElf_Word shnum, const char *name, const char *file, 1627 uint32_t flags) 1628 { 1629 GElf_Word cnt; 1630 1631 for (cnt = 1; cnt < shnum; cnt++) { 1632 ulong_t num, symn; 1633 int ndx; 1634 Elf_Data *dsyms; 1635 const char *fmt; 1636 Cache *_cache = &cache[cnt]; 1637 GElf_Shdr *shdr = &_cache->c_shdr; 1638 char *sname; 1639 1640 if (shdr->sh_type != SHT_SUNW_move) 1641 continue; 1642 if (name && strcmp(name, _cache->c_name)) 1643 continue; 1644 1645 /* 1646 * Determine the move data and number. 1647 */ 1648 if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) { 1649 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 1650 file, _cache->c_name); 1651 (void) fflush(stderr); 1652 continue; 1653 } 1654 num = shdr->sh_size / shdr->sh_entsize; 1655 1656 /* 1657 * Get the data buffer for the associated symbol table. 1658 */ 1659 if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) { 1660 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 1661 file, _cache->c_name, EC_XWORD(shdr->sh_link)); 1662 (void) fflush(stderr); 1663 continue; 1664 } 1665 dsyms = cache[shdr->sh_link].c_data; 1666 if (dsyms->d_buf == 0) { 1667 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 1668 file, cache[shdr->sh_link].c_name); 1669 (void) fflush(stderr); 1670 continue; 1671 } 1672 1673 sname = cache[shdr->sh_link].c_name; 1674 shdr = &cache[shdr->sh_link].c_shdr; 1675 1676 /* 1677 * Get the associated string table section. 1678 */ 1679 if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) { 1680 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 1681 file, sname, EC_XWORD(shdr->sh_link)); 1682 (void) fflush(stderr); 1683 continue; 1684 } 1685 if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) { 1686 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 1687 file, sname); 1688 (void) fflush(stderr); 1689 continue; 1690 } 1691 symn = shdr->sh_size / shdr->sh_entsize; 1692 1693 dbg_print(MSG_ORIG(MSG_STR_EMPTY)); 1694 dbg_print(MSG_INTL(MSG_MV_TITLE), _cache->c_name); 1695 1696 fmt = MSG_INTL(MSG_MV_ENTRY); 1697 1698 /* LINTED */ 1699 for (ndx = 0; ndx < num; ndx++) { 1700 GElf_Move move; 1701 const char *name; 1702 GElf_Sym sym; 1703 char sct[BUFSIZ]; 1704 Word shndx; 1705 1706 if (gelf_getmove(_cache->c_data, ndx, &move) == NULL) { 1707 (void) fprintf(stderr, 1708 MSG_INTL(MSG_ERR_BADMOVE), 1709 file, _cache->c_name, elf_errmsg(0)); 1710 (void) fflush(stderr); 1711 break; 1712 } 1713 1714 /* 1715 * Check for null entries 1716 */ 1717 if ((move.m_info == 0) && (move.m_value == 0) && 1718 (move.m_poffset == 0) && (move.m_repeat == 0) && 1719 (move.m_stride == 0)) { 1720 dbg_print(fmt, EC_XWORD(move.m_poffset), 1721 EC_XWORD(0), 0, 0, 0, EC_LWORD(0), 1722 MSG_ORIG(MSG_STR_EMPTY)); 1723 continue; 1724 } 1725 if ((GELF_M_SYM(move.m_info) == 0) || 1726 (GELF_M_SYM(move.m_info) >= symn)) { 1727 (void) fprintf(stderr, 1728 MSG_INTL(MSG_ERR_BADMINFO), file, 1729 _cache->c_name, EC_XWORD(move.m_info)); 1730 (void) fflush(stderr); 1731 dbg_print(fmt, EC_XWORD(move.m_poffset), 1732 EC_XWORD(GELF_M_SYM(move.m_info)), 1733 /* LINTED */ 1734 GELF_M_SIZE(move.m_info), move.m_repeat, 1735 move.m_stride, EC_LWORD(move.m_value), 1736 MSG_INTL(MSG_STR_UNKNOWN)); 1737 continue; 1738 } 1739 1740 if (gelf_getsym(dsyms, 1741 /* LINTED */ 1742 (int)GELF_M_SYM(move.m_info), &sym) == NULL) { 1743 (void) fprintf(stderr, 1744 MSG_INTL(MSG_ERR_MVBADSYMNDX), 1745 file, elf_errmsg(0)); 1746 (void) fflush(stderr); 1747 name = MSG_INTL(MSG_STR_UNKNOWN); 1748 } else { 1749 if ((GELF_ST_TYPE(sym.st_info) == 1750 STT_SECTION) && (sym.st_name == 0)) { 1751 if (flags & FLG_LONGNAME) 1752 (void) snprintf(sct, BUFSIZ, 1753 MSG_INTL(MSG_STR_L_SECTION), 1754 cache[sym.st_shndx].c_name); 1755 else 1756 (void) snprintf(sct, BUFSIZ, 1757 MSG_INTL(MSG_STR_SECTION), 1758 cache[sym.st_shndx].c_name); 1759 name = (const char *)sct; 1760 } else { 1761 name = demangle(string(_cache, 1762 /* LINTED */ 1763 (GElf_Word)GELF_M_SYM(move.m_info), 1764 &cache[shdr->sh_link], file, 1765 sym.st_name), flags); 1766 } 1767 } 1768 1769 /* 1770 * Additional sanity check. 1771 */ 1772 shndx = sym.st_shndx; 1773 if (!((shndx == SHN_COMMON) || 1774 (((shndx >= 1) && (shndx <= shnum)) && 1775 (cache[shndx].c_shdr).sh_type == SHT_NOBITS))) { 1776 (void) fprintf(stderr, 1777 MSG_INTL(MSG_ERR_BADSYM2), file, 1778 _cache->c_name, name); 1779 (void) fflush(stderr); 1780 } 1781 1782 dbg_print(fmt, EC_XWORD(move.m_poffset), 1783 EC_XWORD(GELF_M_SYM(move.m_info)), 1784 /* LINTED */ 1785 GELF_M_SIZE(move.m_info), move.m_repeat, 1786 move.m_stride, EC_LWORD(move.m_value), name); 1787 } 1788 } 1789 } 1790 1791 /* 1792 * Traverse a note section analyzing each note information block. 1793 * The data buffers size is used to validate references before they are made, 1794 * and is decremented as each element is processed. 1795 */ 1796 void 1797 note_entry(Cache *cache, Word *data, Word size, const char *file) 1798 { 1799 Word bsize = size; 1800 /* 1801 * Print out a single `note' information block. 1802 */ 1803 while (size > 0) { 1804 Word namesz, descsz, type, pad, noteoff; 1805 1806 1807 noteoff = bsize - size; 1808 /* 1809 * Make sure we can at least reference the 3 initial entries 1810 * (4-byte words) of the note information block. 1811 */ 1812 if (size >= (Word)(sizeof (Word) * 3)) 1813 size -= (Word)(sizeof (Word) * 3); 1814 else { 1815 (void) fprintf(stderr, MSG_INTL(MSG_NOTE_BADDATASIZE), 1816 file, cache->c_name, EC_WORD(noteoff)); 1817 (void) fflush(stderr); 1818 return; 1819 } 1820 1821 /* 1822 * Make sure any specified name string can be referenced. 1823 */ 1824 if ((namesz = *data++) != 0) { 1825 if (size >= namesz) 1826 size -= namesz; 1827 else { 1828 (void) fprintf(stderr, 1829 MSG_INTL(MSG_NOTE_BADNMSIZE), 1830 file, cache->c_name, EC_WORD(noteoff), 1831 EC_WORD(namesz)); 1832 (void) fflush(stderr); 1833 return; 1834 } 1835 } 1836 /* 1837 * Make sure any specified descriptor can be referenced. 1838 */ 1839 if ((descsz = *data++) != 0) { 1840 /* 1841 * If namesz isn't a 4-byte multiple, account for any 1842 * padding that must exist before the descriptor. 1843 */ 1844 if ((pad = (namesz & (Word)(sizeof (Word) - 1))) != 0) { 1845 pad = (Word)sizeof (Word) - pad; 1846 size -= pad; 1847 } 1848 if (size >= descsz) 1849 size -= descsz; 1850 else { 1851 (void) fprintf(stderr, 1852 MSG_INTL(MSG_NOTE_BADDESIZE), 1853 file, cache->c_name, EC_WORD(noteoff), 1854 EC_WORD(namesz)); 1855 (void) fflush(stderr); 1856 return; 1857 } 1858 } 1859 1860 type = *data++; 1861 1862 dbg_print(MSG_ORIG(MSG_STR_EMPTY)); 1863 dbg_print(MSG_ORIG(MSG_NOTE_TYPE), EC_WORD(type)); 1864 1865 dbg_print(MSG_ORIG(MSG_NOTE_NAMESZ), EC_WORD(namesz)); 1866 if (namesz) { 1867 char *name = (char *)data; 1868 1869 /* 1870 * Since the name string may have 'null' bytes 1871 * in it (ia32 .string) - we just write the 1872 * whole stream in a single fwrite. 1873 */ 1874 (void) fwrite(name, namesz, 1, stdout); 1875 name = name + ((namesz + (sizeof (Word) - 1)) & 1876 ~(sizeof (Word) - 1)); 1877 /* LINTED */ 1878 data = (Word *)name; 1879 dbg_print(MSG_ORIG(MSG_STR_EMPTY)); 1880 } 1881 1882 /* 1883 * If multiple information blocks exist within a .note section 1884 * account for any padding that must exist before the next 1885 * information block. 1886 */ 1887 if ((pad = (descsz & (Word)(sizeof (Word) - 1))) != 0) { 1888 pad = (Word)sizeof (Word) - pad; 1889 if (size > pad) 1890 size -= pad; 1891 } 1892 1893 dbg_print(MSG_ORIG(MSG_NOTE_DESCSZ), EC_WORD(descsz)); 1894 if (descsz) { 1895 int ndx, byte, word; 1896 char string[58], * str = string; 1897 uchar_t *desc = (uchar_t *)data; 1898 1899 /* 1900 * Dump descriptor bytes. 1901 */ 1902 for (ndx = byte = word = 0; descsz; descsz--, desc++) { 1903 int tok = *desc; 1904 1905 (void) snprintf(str, 58, MSG_ORIG(MSG_NOTE_TOK), 1906 tok); 1907 str += 3; 1908 1909 if (++byte == 4) { 1910 *str++ = ' ', *str++ = ' '; 1911 word++; 1912 byte = 0; 1913 } 1914 if (word == 4) { 1915 *str = '\0'; 1916 dbg_print(MSG_ORIG(MSG_NOTE_DESC), 1917 ndx, string); 1918 word = 0; 1919 ndx += 16; 1920 str = string; 1921 } 1922 } 1923 if (byte || word) { 1924 *str = '\0'; 1925 dbg_print(MSG_ORIG(MSG_NOTE_DESC), ndx, string); 1926 } 1927 1928 desc += pad; 1929 /* LINTED */ 1930 data = (Word *)desc; 1931 } 1932 } 1933 } 1934 1935 /* 1936 * Search for and process a .note section. 1937 */ 1938 static void 1939 note(Cache *cache, GElf_Word shnum, const char *name, const char *file) 1940 { 1941 GElf_Word cnt; 1942 1943 /* 1944 * Otherwise look for any .note sections. 1945 */ 1946 for (cnt = 1; cnt < shnum; cnt++) { 1947 Cache * _cache = &cache[cnt]; 1948 GElf_Shdr * shdr = &_cache->c_shdr; 1949 1950 if (shdr->sh_type != SHT_NOTE) 1951 continue; 1952 if (name && strcmp(name, _cache->c_name)) 1953 continue; 1954 1955 /* 1956 * As these sections are often hand rolled, make sure they're 1957 * properly aligned before proceeding. 1958 */ 1959 if (shdr->sh_offset & (sizeof (Word) - 1)) { 1960 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADALIGN), 1961 file, _cache->c_name); 1962 (void) fflush(stderr); 1963 continue; 1964 } 1965 1966 dbg_print(MSG_ORIG(MSG_STR_EMPTY)); 1967 dbg_print(MSG_INTL(MSG_ELF_SCN_NOTE), _cache->c_name); 1968 note_entry(_cache, (Word *)_cache->c_data->d_buf, 1969 /* LINTED */ 1970 (Word)_cache->c_data->d_size, file); 1971 } 1972 } 1973 1974 1975 #define MAXCOUNT 500 1976 1977 static void 1978 hash(Cache *cache, GElf_Word shnum, const char *name, const char *file, 1979 uint32_t flags) 1980 { 1981 static int count[MAXCOUNT]; 1982 GElf_Word cnt; 1983 ulong_t ndx, bkts; 1984 char number[MAXNDXSIZE]; 1985 1986 for (cnt = 1; cnt < shnum; cnt++) { 1987 uint_t *hash, *chain; 1988 Elf_Data *dsyms; 1989 Cache *_cache = &cache[cnt]; 1990 GElf_Shdr *shdr = &_cache->c_shdr; 1991 char *sname; 1992 1993 if (shdr->sh_type != SHT_HASH) 1994 continue; 1995 if (name && strcmp(name, _cache->c_name)) 1996 continue; 1997 1998 /* 1999 * Determine the hash table data and size. 2000 */ 2001 if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) { 2002 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 2003 file, _cache->c_name); 2004 (void) fflush(stderr); 2005 continue; 2006 } 2007 hash = (uint_t *)_cache->c_data->d_buf; 2008 bkts = *hash; 2009 chain = hash + 2 + bkts; 2010 hash += 2; 2011 2012 /* 2013 * Get the data buffer for the associated symbol table. 2014 */ 2015 if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) { 2016 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 2017 file, _cache->c_name, EC_XWORD(shdr->sh_link)); 2018 (void) fflush(stderr); 2019 continue; 2020 } 2021 dsyms = cache[shdr->sh_link].c_data; 2022 if (dsyms->d_buf == 0) { 2023 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 2024 file, cache[shdr->sh_link].c_name); 2025 (void) fflush(stderr); 2026 continue; 2027 } 2028 2029 sname = cache[shdr->sh_link].c_name; 2030 shdr = &cache[shdr->sh_link].c_shdr; 2031 /* 2032 * Get the associated string table section. 2033 */ 2034 if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) { 2035 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 2036 file, sname, EC_XWORD(shdr->sh_link)); 2037 (void) fflush(stderr); 2038 continue; 2039 } 2040 2041 dbg_print(MSG_ORIG(MSG_STR_EMPTY)); 2042 dbg_print(MSG_INTL(MSG_ELF_SCN_HASH), _cache->c_name); 2043 dbg_print(MSG_INTL(MSG_ELF_HASH_INFO)); 2044 2045 /* 2046 * Loop through the hash buckets, printing the appropriate 2047 * symbols. 2048 */ 2049 for (ndx = 0; ndx < bkts; ndx++, hash++) { 2050 GElf_Sym _sym; 2051 const char *_str; 2052 GElf_Word _ndx, _cnt; 2053 char _number[MAXNDXSIZE]; 2054 ulong_t nbkt, nhash; 2055 2056 if (*hash == 0) { 2057 count[0]++; 2058 continue; 2059 } 2060 2061 /* LINTED */ 2062 if (gelf_getsym(dsyms, (int)*hash, &_sym) == NULL) { 2063 (void) fprintf(stderr, 2064 MSG_INTL(MSG_ERR_HSBADSYMNDX), 2065 file, elf_errmsg(0)); 2066 (void) fflush(stderr); 2067 _str = MSG_INTL(MSG_STR_UNKNOWN); 2068 } else { 2069 _str = string(_cache, (GElf_Word)*hash, 2070 &cache[shdr->sh_link], file, 2071 _sym.st_name); 2072 } 2073 2074 (void) snprintf(number, MAXNDXSIZE, 2075 /* LINTED */ 2076 MSG_ORIG(MSG_FMT_INTEGER), (int)ndx); 2077 (void) snprintf(_number, MAXNDXSIZE, 2078 MSG_ORIG(MSG_FMT_INDEX2), EC_XWORD(*hash)); 2079 dbg_print(MSG_ORIG(MSG_FMT_HASH_INFO), number, _number, 2080 demangle(_str, flags)); 2081 2082 /* 2083 * Determine if this string is in the correct bucket. 2084 */ 2085 nhash = elf_hash(_str); 2086 nbkt = nhash % bkts; 2087 if (nbkt != ndx) { 2088 (void) fprintf(stderr, 2089 MSG_INTL(MSG_ERR_BADHASH), file, 2090 /* LINTED */ 2091 _cache->c_name, _str, (int)ndx, (int)nbkt); 2092 (void) fflush(stderr); 2093 } 2094 2095 /* 2096 * Determine if any other symbols are chained to this 2097 * bucket. 2098 */ 2099 _ndx = chain[*hash]; 2100 _cnt = 1; 2101 while (_ndx) { 2102 /* LINTED */ 2103 if (gelf_getsym(dsyms, (int)_ndx, 2104 &_sym) == NULL) { 2105 (void) fprintf(stderr, 2106 MSG_INTL(MSG_ERR_HSBADSYMNDX), 2107 file, elf_errmsg(0)); 2108 (void) fflush(stderr); 2109 _str = MSG_INTL(MSG_STR_UNKNOWN); 2110 } else 2111 _str = string(_cache, _ndx, 2112 &cache[shdr->sh_link], file, 2113 _sym.st_name); 2114 2115 (void) snprintf(_number, MAXNDXSIZE, 2116 MSG_ORIG(MSG_FMT_INDEX2), EC_XWORD(_ndx)); 2117 dbg_print(MSG_ORIG(MSG_FMT_HASH_INFO), 2118 MSG_ORIG(MSG_STR_EMPTY), _number, 2119 demangle(_str, flags)); 2120 _ndx = chain[_ndx]; 2121 _cnt++; 2122 2123 /* 2124 * Determine if this string is in the correct 2125 * bucket. 2126 */ 2127 nhash = elf_hash(_str); 2128 nbkt = nhash % bkts; 2129 if (nbkt != ndx) { 2130 (void) fprintf(stderr, 2131 MSG_INTL(MSG_ERR_BADHASH), file, 2132 _cache->c_name, _str, 2133 /* LINTED */ 2134 (int)ndx, (int)nbkt); 2135 (void) fflush(stderr); 2136 } 2137 } 2138 2139 if (_cnt >= MAXCOUNT) { 2140 (void) fprintf(stderr, 2141 MSG_INTL(MSG_HASH_OVERFLW), 2142 /* LINTED */ 2143 (int)ndx, _cnt); 2144 (void) fflush(stderr); 2145 } else 2146 count[_cnt]++; 2147 } 2148 break; 2149 } 2150 2151 /* 2152 * Print out the count information. 2153 */ 2154 bkts = cnt = 0; 2155 dbg_print(MSG_ORIG(MSG_STR_EMPTY)); 2156 for (ndx = 0; ndx < MAXCOUNT; ndx++) { 2157 GElf_Word _cnt; 2158 2159 if ((_cnt = count[ndx]) == 0) 2160 continue; 2161 2162 (void) snprintf(number, MAXNDXSIZE, MSG_ORIG(MSG_FMT_INTEGER), 2163 /* LINTED */ 2164 (int)_cnt); 2165 /* LINTED */ 2166 dbg_print(MSG_INTL(MSG_ELF_HASH_BKTS1), number, (int)ndx); 2167 bkts += _cnt; 2168 /* LINTED */ 2169 cnt += (GElf_Word)(ndx * _cnt); 2170 } 2171 if (cnt) { 2172 (void) snprintf(number, MAXNDXSIZE, MSG_ORIG(MSG_FMT_INTEGER), 2173 /* LINTED */ 2174 (int)bkts); 2175 /* LINTED */ 2176 dbg_print(MSG_INTL(MSG_ELF_HASH_BKTS2), number, (int)cnt); 2177 } 2178 } 2179 2180 2181 static void 2182 group(Cache *cache, GElf_Word shnum, const char *name, const char *file, 2183 uint32_t flags) 2184 { 2185 GElf_Word cnt; 2186 2187 for (cnt = 1; cnt < shnum; cnt++) { 2188 Cache *_cache = &cache[cnt]; 2189 GElf_Shdr *shdr = &_cache->c_shdr; 2190 Elf_Data *dsyms; 2191 GElf_Shdr *symshdr; 2192 GElf_Sym sym; 2193 const char *symname; 2194 char flgstrbuf[MSG_GRP_COMDAT_SIZE + 10]; 2195 Word *grpdata; 2196 size_t _cnt; 2197 size_t grpcnt; 2198 2199 2200 if (shdr->sh_type != SHT_GROUP) 2201 continue; 2202 if (name && strcmp(name, _cache->c_name)) 2203 continue; 2204 dbg_print(MSG_INTL(MSG_GRP_LINE1), _cache->c_name); 2205 if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) { 2206 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 2207 file, _cache->c_name, EC_XWORD(shdr->sh_link)); 2208 (void) fflush(stderr); 2209 continue; 2210 } 2211 2212 if (shdr->sh_entsize != sizeof (Word)) { 2213 (void) fprintf(stderr, MSG_INTL(MSG_GRP_BADENTSZ), 2214 file, _cache->c_name, 2215 EC_XWORD(shdr->sh_entsize)); 2216 (void) fflush(stderr); 2217 } 2218 symshdr = &(cache[shdr->sh_link].c_shdr); 2219 if ((symshdr->sh_type != SHT_SYMTAB) && 2220 (symshdr->sh_type != SHT_DYNSYM)) { 2221 (void) fprintf(stderr, MSG_INTL(MSG_GRP_NOTSYMTAB), 2222 file, _cache->c_name, EC_XWORD(shdr->sh_link)); 2223 (void) fflush(stderr); 2224 continue; 2225 } 2226 dsyms = cache[shdr->sh_link].c_data; 2227 if ((shdr->sh_info == SHN_UNDEF) || ((ulong_t)shdr->sh_info > 2228 (symshdr->sh_size / symshdr->sh_entsize))) { 2229 (void) fprintf(stderr, MSG_INTL(MSG_GRP_BADSYMNDX), 2230 file, _cache->c_name, EC_XWORD(shdr->sh_info)); 2231 (void) fflush(stderr); 2232 continue; 2233 } 2234 flgstrbuf[0] = '['; 2235 flgstrbuf[1] = '\0'; 2236 if ((shdr->sh_size != 0) && 2237 (_cache->c_data) && 2238 ((grpdata = (Word *)_cache->c_data->d_buf) != 0)) { 2239 if (grpdata[0] & GRP_COMDAT) { 2240 (void) strcat(flgstrbuf, 2241 MSG_ORIG(MSG_GRP_COMDAT)); 2242 } 2243 if ((grpdata[0] & ~GRP_COMDAT) != 0) { 2244 (void) snprintf(flgstrbuf + strlen(flgstrbuf), 2245 (MSG_GRP_COMDAT_SIZE + 10), 2246 MSG_ORIG(MSG_GRP_FMT1), 2247 (uint_t)(grpdata[0] & ~GRP_COMDAT)); 2248 } 2249 } 2250 (void) strcat(flgstrbuf, MSG_ORIG(MSG_GRP_CLOSBRKT)); 2251 2252 if (gelf_getsym(dsyms, shdr->sh_info, &sym) == NULL) { 2253 (void) fprintf(stderr, 2254 MSG_INTL(MSG_ERR_GRBADSYMNDX), 2255 file, elf_errmsg(0)); 2256 (void) fflush(stderr); 2257 } 2258 symname = demangle(string(_cache, shdr->sh_link, 2259 &cache[symshdr->sh_link], file, sym.st_name), 2260 flags); 2261 dbg_print(MSG_INTL(MSG_GRP_LINE2)); 2262 dbg_print(MSG_INTL(MSG_GRP_LINE3), 2263 flgstrbuf, symname); 2264 for (_cnt = 1, grpcnt = (shdr->sh_size / sizeof (Word)); 2265 _cnt < grpcnt; _cnt++) { 2266 char index[MAXNDXSIZE]; 2267 const char *sname; 2268 2269 (void) snprintf(index, MAXNDXSIZE, 2270 MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(_cnt)); 2271 if (grpdata[_cnt] >= shnum) { 2272 sname = MSG_INTL(MSG_GRP_INVALSCN); 2273 } else { 2274 sname = cache[grpdata[_cnt]].c_name; 2275 } 2276 (void) printf(MSG_ORIG(MSG_GRP_FMT2), index, sname, 2277 (uint_t)grpdata[_cnt]); 2278 } 2279 } 2280 } 2281 2282 2283 static void 2284 got(Cache *cache, GElf_Word shnum, GElf_Ehdr *ehdr, const char *file) 2285 { 2286 Cache *gotcache = 0, *symtab = 0, *_cache; 2287 GElf_Addr gotbgn, gotend; 2288 GElf_Shdr *gotshdr; 2289 GElf_Word cnt, gotents, gotndx; 2290 size_t gentsize; 2291 Got_info *gottable; 2292 char *gotdata; 2293 GElf_Sym gsym; 2294 GElf_Xword gsymaddr; 2295 2296 /* 2297 * First we find the got 2298 */ 2299 for (cnt = 1; cnt < shnum; cnt++) { 2300 _cache = &cache[cnt]; 2301 if (strncmp(_cache->c_name, MSG_ORIG(MSG_ELF_GOT), 4) == 0) { 2302 gotcache = _cache; 2303 break; 2304 } 2305 } 2306 if (!gotcache) 2307 return; 2308 gotshdr = &gotcache->c_shdr; 2309 gotbgn = gotshdr->sh_addr; 2310 2311 if (gotshdr->sh_size == 0) { 2312 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 2313 file, gotcache->c_name); 2314 (void) fflush(stderr); 2315 return; 2316 } 2317 gotend = gotbgn + gotshdr->sh_size; 2318 2319 /* 2320 * Some architectures don't properly set the sh_entsize 2321 * for the GOT table. If it's not set we will default 2322 * to a size of a pointer. 2323 */ 2324 if ((gentsize = gotshdr->sh_entsize) == 0) { 2325 if (ehdr->e_ident[EI_CLASS] == ELFCLASS64) 2326 gentsize = sizeof (GElf_Xword); 2327 else 2328 gentsize = sizeof (GElf_Word); 2329 } 2330 /* LINTED */ 2331 gotents = (GElf_Word)(gotshdr->sh_size / gentsize); 2332 gotdata = gotcache->c_data->d_buf; 2333 2334 if ((gottable = calloc(gotents, sizeof (Got_info))) == 0) { 2335 int err = errno; 2336 (void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC), 2337 file, strerror(err)); 2338 (void) fflush(stderr); 2339 return; 2340 } 2341 2342 /* 2343 * Now we scan through all the sections looking for any relocations 2344 * that may be against the GOT. Since these may not be isolated to a 2345 * .rel[a].got section we check them all. 2346 * While scanning sections save the symbol table entry (a symtab 2347 * overriding a dynsym) so that we can lookup _GLOBAL_OFFSET_TABLE_. 2348 */ 2349 for (cnt = 1; cnt < shnum; cnt++) { 2350 GElf_Shdr *shdr; 2351 GElf_Word rtype; 2352 Elf_Data *dsyms, *reldata; 2353 GElf_Rela rela; 2354 ulong_t rcount; 2355 int ndx; 2356 char *sname; 2357 2358 _cache = &cache[cnt]; 2359 shdr = &_cache->c_shdr; 2360 2361 if ((symtab == 0) && (shdr->sh_type == SHT_DYNSYM)) { 2362 symtab = _cache; 2363 continue; 2364 } 2365 if (shdr->sh_type == SHT_SYMTAB) { 2366 symtab = _cache; 2367 continue; 2368 } 2369 2370 rtype = shdr->sh_type; 2371 if ((rtype != SHT_RELA) && (rtype != SHT_REL)) 2372 continue; 2373 2374 /* 2375 * Determine the relocation data and number. 2376 */ 2377 if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) { 2378 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 2379 file, _cache->c_name); 2380 (void) fflush(stderr); 2381 continue; 2382 } 2383 rcount = shdr->sh_size / shdr->sh_entsize; 2384 2385 reldata = _cache->c_data; 2386 2387 /* 2388 * Get the data buffer for the associated symbol table. 2389 */ 2390 if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) { 2391 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 2392 file, _cache->c_name, EC_XWORD(shdr->sh_link)); 2393 (void) fflush(stderr); 2394 continue; 2395 } 2396 dsyms = cache[shdr->sh_link].c_data; 2397 if (dsyms->d_buf == 0) { 2398 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 2399 file, cache[shdr->sh_link].c_name); 2400 (void) fflush(stderr); 2401 continue; 2402 } 2403 2404 sname = cache[shdr->sh_link].c_name; 2405 shdr = &cache[shdr->sh_link].c_shdr; 2406 /* 2407 * Get the associated string table section. 2408 */ 2409 if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) { 2410 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 2411 file, sname, EC_XWORD(shdr->sh_link)); 2412 (void) fflush(stderr); 2413 continue; 2414 } 2415 2416 /* LINTED */ 2417 for (ndx = 0; ndx < rcount; ++ndx) { 2418 GElf_Sym _sym; 2419 GElf_Word sndx; 2420 GElf_Addr offset; 2421 Got_info *gip; 2422 void *relret; 2423 2424 if (rtype == SHT_RELA) { 2425 relret = (void *)gelf_getrela(reldata, ndx, 2426 &rela); 2427 } else { 2428 relret = (void *)gelf_getrel(reldata, ndx, 2429 (GElf_Rel *)&rela); 2430 } 2431 if (relret == NULL) { 2432 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADREL), 2433 file, _cache->c_name, elf_errmsg(0)); 2434 (void) fflush(stderr); 2435 break; 2436 } 2437 2438 offset = rela.r_offset; 2439 /* LINTED */ 2440 sndx = (GElf_Word)GELF_R_SYM(rela.r_info); 2441 2442 /* 2443 * Only pay attention to relocations against the GOT. 2444 */ 2445 if ((offset < gotbgn) || (offset > gotend)) 2446 continue; 2447 2448 /* LINTED */ 2449 gotndx = (GElf_Word)((offset - gotbgn) / 2450 gotshdr->sh_entsize); 2451 gip = &gottable[gotndx]; 2452 if (gip->g_rshtype != 0) { 2453 (void) fprintf(stderr, 2454 MSG_INTL(MSG_GOT_MULTIPLE), file, 2455 /* LINTED */ 2456 EC_WORD(gotndx), EC_XWORD(offset)); 2457 (void) fflush(stderr); 2458 continue; 2459 } 2460 2461 /* LINTED */ 2462 if (gelf_getsym(dsyms, sndx, &_sym) == NULL) { 2463 (void) fprintf(stderr, 2464 MSG_INTL(MSG_ERR_RELBADSYMNDX), 2465 file, elf_errmsg(0)); 2466 (void) fflush(stderr); 2467 gip->g_symname = MSG_INTL(MSG_STR_UNKNOWN); 2468 } else { 2469 gip->g_symname = string(_cache, sndx, 2470 &cache[shdr->sh_link], file, _sym.st_name); 2471 } 2472 gip->g_rshtype = rtype; 2473 gip->g_rela = rela; 2474 } 2475 } 2476 2477 if (symlookup(MSG_ORIG(MSG_GOT_SYM), cache, shnum, &gsym, symtab, file)) 2478 gsymaddr = gsym.st_value; 2479 else 2480 gsymaddr = gotbgn; 2481 2482 dbg_print(MSG_ORIG(MSG_STR_EMPTY)); 2483 dbg_print(MSG_INTL(MSG_ELF_SCN_GOT), gotcache->c_name, gotents); 2484 Gelf_got_title(ehdr->e_ident[EI_CLASS]); 2485 2486 for (gotndx = 0; gotndx < gotents; gotndx++) { 2487 Got_info *gip; 2488 Sword gindex; 2489 GElf_Addr gaddr; 2490 GElf_Xword gotentry; 2491 2492 gip = &gottable[gotndx]; 2493 2494 gaddr = gotbgn + (gotndx * gentsize); 2495 /* LINTED */ 2496 gindex = (Sword)((gaddr - gsymaddr) / gentsize); 2497 2498 if (gentsize == sizeof (GElf_Word)) 2499 /* LINTED */ 2500 gotentry = (GElf_Xword)(*((GElf_Word *)(gotdata) + 2501 gotndx)); 2502 else 2503 /* LINTED */ 2504 gotentry = *((GElf_Xword *)(gotdata) + gotndx); 2505 2506 Gelf_got_entry(ehdr, gindex, gaddr, gotentry, gip->g_rshtype, 2507 &gip->g_rela, gip->g_symname); 2508 } 2509 2510 free(gottable); 2511 } 2512 2513 void 2514 checksum(Elf *elf) 2515 { 2516 dbg_print(MSG_ORIG(MSG_STR_EMPTY)); 2517 dbg_print(MSG_INTL(MSG_STR_CHECKSUM), gelf_checksum(elf)); 2518 } 2519 2520 static void 2521 regular(const char *file, Elf *elf, uint32_t flags, char *Nname, int wfd) 2522 { 2523 Elf_Scn *scn; 2524 GElf_Ehdr ehdr; 2525 Elf_Data *data; 2526 uint_t cnt; 2527 GElf_Word shnum; 2528 size_t shstrndx, _shnum; 2529 GElf_Shdr nameshdr; 2530 GElf_Shdr shdr0; 2531 GElf_Shdr *_shdr0; 2532 char *names = 0; 2533 Cache *cache, *_cache; 2534 Cache *versymcache; 2535 2536 if (gelf_getehdr(elf, &ehdr) == NULL) { 2537 failure(file, MSG_ORIG(MSG_ELF_GETEHDR)); 2538 return; 2539 } 2540 2541 if (elf_getshnum(elf, &_shnum) == NULL) { 2542 failure(file, MSG_ORIG(MSG_ELF_GETSHNUM)); 2543 return; 2544 } 2545 /* LINTED */ 2546 shnum = (GElf_Word)_shnum; 2547 2548 if (elf_getshstrndx(elf, &shstrndx) == NULL) { 2549 failure(file, MSG_ORIG(MSG_ELF_GETSHSTRNDX)); 2550 return; 2551 } 2552 if ((scn = elf_getscn(elf, 0)) != NULL) { 2553 if ((_shdr0 = gelf_getshdr(scn, &shdr0)) == NULL) { 2554 failure(file, MSG_ORIG(MSG_ELF_GETSHDR)); 2555 (void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SCN), 0); 2556 (void) fflush(stderr); 2557 return; 2558 } 2559 } else 2560 _shdr0 = 0; 2561 2562 /* 2563 * Print the elf header. 2564 */ 2565 if (flags & FLG_EHDR) 2566 Gelf_elf_header(&ehdr, _shdr0); 2567 2568 /* 2569 * Print the program headers. 2570 */ 2571 if ((flags & FLG_PHDR) && ehdr.e_phnum) { 2572 GElf_Phdr phdr; 2573 2574 for (cnt = 0; cnt < ehdr.e_phnum; cnt++) { 2575 if (gelf_getphdr(elf, cnt, &phdr) == NULL) { 2576 failure(file, MSG_ORIG(MSG_ELF_GETPHDR)); 2577 return; 2578 } 2579 2580 dbg_print(MSG_ORIG(MSG_STR_EMPTY)); 2581 dbg_print(MSG_INTL(MSG_ELF_PHDR), cnt); 2582 Gelf_phdr_entry(ehdr.e_machine, &phdr); 2583 } 2584 } 2585 2586 2587 /* 2588 * If there are no sections (core files), or if we don't want 2589 * any section information we might as well return now. 2590 */ 2591 if ((shnum == 0) || (flags && (flags & ~(FLG_EHDR | FLG_PHDR)) == 0)) { 2592 if ((ehdr.e_type == ET_CORE) && (flags & FLG_NOTE)) 2593 note(0, shnum, 0, file); 2594 return; 2595 } 2596 2597 2598 /* 2599 * Obtain the .shstrtab data buffer to provide the required section 2600 * name strings. 2601 */ 2602 if ((scn = elf_getscn(elf, shstrndx)) == NULL) { 2603 failure(file, MSG_ORIG(MSG_ELF_GETSCN)); 2604 (void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SHDR), 2605 EC_XWORD(shstrndx)); 2606 (void) fflush(stderr); 2607 } else if ((data = elf_getdata(scn, NULL)) == NULL) { 2608 failure(file, MSG_ORIG(MSG_ELF_GETDATA)); 2609 (void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_DATA), 2610 EC_XWORD(shstrndx)); 2611 (void) fflush(stderr); 2612 } else if (gelf_getshdr(scn, &nameshdr) == NULL) { 2613 failure(file, MSG_ORIG(MSG_ELF_GETSHDR)); 2614 (void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SCN), 2615 /* LINTED */ 2616 (int)elf_ndxscn(scn)); 2617 (void) fflush(stderr); 2618 } else if ((names = data->d_buf) == 0) { 2619 (void) fprintf(stderr, MSG_INTL(MSG_ERR_SHSTRNULL), file); 2620 (void) fflush(stderr); 2621 } 2622 2623 /* 2624 * Fill in the cache descriptor with information for each section. 2625 */ 2626 if ((cache = malloc(shnum * sizeof (Cache))) == 0) { 2627 int err = errno; 2628 (void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC), 2629 file, strerror(err)); 2630 (void) fflush(stderr); 2631 return; 2632 } 2633 2634 *cache = _cache_init; 2635 _cache = cache; 2636 _cache++; 2637 2638 for (cnt = 1, scn = NULL; scn = elf_nextscn(elf, scn); 2639 cnt++, _cache++) { 2640 if (gelf_getshdr(scn, &_cache->c_shdr) == NULL) { 2641 failure(file, MSG_ORIG(MSG_ELF_GETSHDR)); 2642 (void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SCN), 2643 /* LINTED */ 2644 (int)elf_ndxscn(scn)); 2645 (void) fflush(stderr); 2646 } 2647 2648 if (names && _cache->c_shdr.sh_name && 2649 /* LINTED */ 2650 (nameshdr.sh_size > _cache->c_shdr.sh_name)) 2651 _cache->c_name = names + _cache->c_shdr.sh_name; 2652 else { 2653 /* 2654 * If there exists no shstrtab data, or a section header 2655 * has no name (an invalid index of 0), then compose a 2656 * name for each section. 2657 */ 2658 char scnndxnm[100]; 2659 2660 (void) snprintf(scnndxnm, 100, MSG_INTL(MSG_FMT_SCNNDX), 2661 cnt); 2662 2663 /* 2664 * Although we have a valid shstrtab section inform the 2665 * user if this section name index exceeds the shstrtab 2666 * data. 2667 */ 2668 if (names && 2669 /* LINTED */ 2670 (nameshdr.sh_size <= _cache->c_shdr.sh_name)) { 2671 (void) fprintf(stderr, 2672 MSG_INTL(MSG_ERR_BADSHNAME), file, 2673 _cache->c_name, 2674 EC_XWORD(_cache->c_shdr.sh_name)); 2675 (void) fflush(stderr); 2676 } 2677 2678 if ((_cache->c_name = 2679 malloc(strlen(scnndxnm) + 1)) == 0) { 2680 int err = errno; 2681 (void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC), 2682 file, strerror(err)); 2683 (void) fflush(stderr); 2684 return; 2685 } 2686 (void) strcpy(_cache->c_name, scnndxnm); 2687 } 2688 2689 if ((_cache->c_data = elf_getdata(scn, NULL)) == NULL) { 2690 failure(file, MSG_ORIG(MSG_ELF_GETDATA)); 2691 (void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SCNDATA), 2692 /* LINTED */ 2693 (int)elf_ndxscn(scn)); 2694 (void) fflush(stderr); 2695 } 2696 2697 /* 2698 * Do we wish to write the section out? 2699 */ 2700 if (wfd && Nname && (strcmp(Nname, _cache->c_name) == 0)) { 2701 (void) write(wfd, _cache->c_data->d_buf, 2702 _cache->c_data->d_size); 2703 } 2704 } 2705 2706 if (flags & FLG_SHDR) 2707 sections(file, cache, shnum, &ehdr, Nname); 2708 2709 if (flags & FLG_INTERP) 2710 interp(file, cache, shnum, &ehdr, elf); 2711 2712 versymcache = versions(cache, shnum, file, flags); 2713 2714 if (flags & FLG_SYMBOLS) 2715 symbols(cache, shnum, &ehdr, Nname, versymcache, file); 2716 2717 if (flags & FLG_HASH) 2718 hash(cache, shnum, Nname, file, flags); 2719 2720 if (flags & FLG_GOT) 2721 got(cache, shnum, &ehdr, file); 2722 2723 if (flags & FLG_GROUP) 2724 group(cache, shnum, Nname, file, flags); 2725 2726 if (flags & FLG_SYMINFO) 2727 syminfo(cache, shnum, file); 2728 2729 if (flags & FLG_RELOC) 2730 reloc(cache, shnum, &ehdr, Nname, file, flags); 2731 2732 if (flags & FLG_DYNAMIC) 2733 dynamic(cache, shnum, &ehdr, file); 2734 2735 if (flags & FLG_NOTE) 2736 note(cache, shnum, Nname, file); 2737 2738 if (flags & FLG_MOVE) 2739 move(cache, shnum, Nname, file, flags); 2740 2741 if (flags & FLG_CHECKSUM) 2742 checksum(elf); 2743 2744 if (flags & FLG_CAP) 2745 cap(file, cache, shnum, &ehdr, elf); 2746 2747 if (flags & FLG_UNWIND) 2748 unwind(cache, shnum, &ehdr, Nname, file, elf); 2749 2750 free(cache); 2751 } 2752 2753 static void 2754 archive(const char *file, int fd, Elf *elf, uint32_t flags, char *Nname, 2755 int wfd) 2756 { 2757 Elf_Cmd cmd = ELF_C_READ; 2758 Elf_Arhdr *arhdr; 2759 Elf *_elf = 0; 2760 size_t ptr; 2761 Elf_Arsym *arsym = 0; 2762 2763 /* 2764 * Determine if the archive sysmbol table itself is required. 2765 */ 2766 if ((flags & FLG_SYMBOLS) && ((Nname == NULL) || 2767 (strcmp(Nname, MSG_ORIG(MSG_ELF_ARSYM)) == 0))) { 2768 /* 2769 * Get the archive symbol table. 2770 */ 2771 if (((arsym = elf_getarsym(elf, &ptr)) == 0) && elf_errno()) { 2772 /* 2773 * The arsym could be 0 even though there was no error. 2774 * Print the error message only when there was 2775 * real error from elf_getarsym(). 2776 */ 2777 failure(file, MSG_ORIG(MSG_ELF_GETARSYM)); 2778 return; 2779 } 2780 } 2781 2782 /* 2783 * Print the archive symbol table only when the archive symbol 2784 * table exists and it was requested to print. 2785 */ 2786 if (arsym) { 2787 size_t cnt; 2788 char index[MAXNDXSIZE]; 2789 size_t offset = 0, _offset = 0; 2790 2791 /* 2792 * Print out all the symbol entries. 2793 */ 2794 dbg_print(MSG_INTL(MSG_ARCHIVE_SYMTAB)); 2795 dbg_print(MSG_INTL(MSG_ARCHIVE_FIELDS)); 2796 2797 for (cnt = 0; cnt < ptr; cnt++, arsym++) { 2798 /* 2799 * For each object obtain an elf descriptor so that we 2800 * can establish the members name. Note, we have had 2801 * archives where the archive header has not been 2802 * obtainable so be lenient with errors. 2803 */ 2804 if ((offset == 0) || ((arsym->as_off != 0) && 2805 (arsym->as_off != _offset))) { 2806 2807 if (_elf) 2808 (void) elf_end(_elf); 2809 2810 if (elf_rand(elf, arsym->as_off) != 2811 arsym->as_off) { 2812 failure(file, MSG_ORIG(MSG_ELF_RAND)); 2813 arhdr = 0; 2814 } else if ((_elf = elf_begin(fd, 2815 ELF_C_READ, elf)) == 0) { 2816 failure(file, MSG_ORIG(MSG_ELF_BEGIN)); 2817 arhdr = 0; 2818 } else if ((arhdr = elf_getarhdr(_elf)) == 0) { 2819 failure(file, 2820 MSG_ORIG(MSG_ELF_GETARHDR)); 2821 arhdr = 0; 2822 } 2823 2824 _offset = arsym->as_off; 2825 if (offset == 0) 2826 offset = _offset; 2827 } 2828 2829 (void) snprintf(index, MAXNDXSIZE, 2830 MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(cnt)); 2831 if (arsym->as_off) 2832 dbg_print(MSG_ORIG(MSG_FMT_ARSYM1), index, 2833 /* LINTED */ 2834 (int)arsym->as_off, arhdr ? arhdr->ar_name : 2835 MSG_INTL(MSG_STR_UNKNOWN), (arsym->as_name ? 2836 demangle(arsym->as_name, flags) : 2837 MSG_INTL(MSG_STR_NULL))); 2838 else 2839 dbg_print(MSG_ORIG(MSG_FMT_ARSYM2), index, 2840 /* LINTED */ 2841 (int)arsym->as_off); 2842 } 2843 2844 if (_elf) 2845 (void) elf_end(_elf); 2846 2847 /* 2848 * If we only need the archive symbol table return. 2849 */ 2850 if ((flags & FLG_SYMBOLS) && Nname && 2851 (strcmp(Nname, MSG_ORIG(MSG_ELF_ARSYM)) == 0)) 2852 return; 2853 2854 /* 2855 * Reset elf descriptor in preparation for processing each 2856 * member. 2857 */ 2858 if (offset) 2859 (void) elf_rand(elf, offset); 2860 } 2861 2862 /* 2863 * Process each object within the archive. 2864 */ 2865 while ((_elf = elf_begin(fd, cmd, elf)) != NULL) { 2866 char name[MAXPATHLEN]; 2867 2868 if ((arhdr = elf_getarhdr(_elf)) == NULL) { 2869 failure(file, MSG_ORIG(MSG_ELF_GETARHDR)); 2870 return; 2871 } 2872 if (*arhdr->ar_name != '/') { 2873 (void) snprintf(name, MAXPATHLEN, 2874 MSG_ORIG(MSG_FMT_ARNAME), file, arhdr->ar_name); 2875 dbg_print(MSG_ORIG(MSG_FMT_NLSTR), name); 2876 2877 switch (elf_kind(_elf)) { 2878 case ELF_K_AR: 2879 archive(name, fd, _elf, flags, Nname, wfd); 2880 break; 2881 case ELF_K_ELF: 2882 regular(name, _elf, flags, Nname, wfd); 2883 break; 2884 default: 2885 (void) fprintf(stderr, 2886 MSG_INTL(MSG_ERR_BADFILE), name); 2887 (void) fflush(stderr); 2888 break; 2889 } 2890 } 2891 2892 cmd = elf_next(_elf); 2893 (void) elf_end(_elf); 2894 } 2895 } 2896 2897 int 2898 main(int argc, char **argv, char **envp) 2899 { 2900 Elf *elf; 2901 int var, fd, wfd = 0; 2902 char *Nname = NULL, *wname = 0; 2903 uint32_t flags = 0, dbg_flags = 0; 2904 2905 /* 2906 * If we're on a 64-bit kernel, try to exec a full 64-bit version of 2907 * the binary. If successful, conv_check_native() won't return. 2908 */ 2909 conv_check_native(argv, envp); 2910 2911 /* 2912 * Establish locale. 2913 */ 2914 (void) setlocale(LC_MESSAGES, MSG_ORIG(MSG_STR_EMPTY)); 2915 (void) textdomain(MSG_ORIG(MSG_SUNW_OST_SGS)); 2916 2917 (void) setvbuf(stdout, NULL, _IOLBF, 0); 2918 (void) setvbuf(stderr, NULL, _IOLBF, 0); 2919 2920 opterr = 0; 2921 while ((var = getopt(argc, argv, MSG_ORIG(MSG_STR_OPTIONS))) != EOF) { 2922 switch (var) { 2923 case 'C': 2924 flags |= FLG_DEMANGLE; 2925 break; 2926 case 'c': 2927 flags |= FLG_SHDR; 2928 break; 2929 case 'd': 2930 flags |= FLG_DYNAMIC; 2931 break; 2932 case 'e': 2933 flags |= FLG_EHDR; 2934 break; 2935 case 'G': 2936 flags |= FLG_GOT; 2937 break; 2938 case 'g': 2939 flags |= FLG_GROUP; 2940 break; 2941 case 'H': 2942 flags |= FLG_CAP; 2943 break; 2944 case 'h': 2945 flags |= FLG_HASH; 2946 break; 2947 case 'i': 2948 flags |= FLG_INTERP; 2949 break; 2950 case 'k': 2951 flags |= FLG_CHECKSUM; 2952 break; 2953 case 'l': 2954 flags |= FLG_LONGNAME; 2955 break; 2956 case 'm': 2957 flags |= FLG_MOVE; 2958 break; 2959 case 'N': 2960 Nname = optarg; 2961 break; 2962 case 'n': 2963 flags |= FLG_NOTE; 2964 break; 2965 case 'p': 2966 flags |= FLG_PHDR; 2967 break; 2968 case 'r': 2969 flags |= FLG_RELOC; 2970 break; 2971 case 's': 2972 flags |= FLG_SYMBOLS; 2973 break; 2974 case 'u': 2975 flags |= FLG_UNWIND; 2976 break; 2977 case 'v': 2978 flags |= FLG_VERSIONS; 2979 break; 2980 case 'w': 2981 wname = optarg; 2982 break; 2983 case 'y': 2984 flags |= FLG_SYMINFO; 2985 break; 2986 case '?': 2987 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF), 2988 basename(argv[0])); 2989 detail_usage(); 2990 return (1); 2991 default: 2992 break; 2993 } 2994 } 2995 2996 /* 2997 * Validate any arguments. 2998 */ 2999 if (flags == 0) { 3000 if (!wname && !Nname) { 3001 flags = FLG_EVERYTHING; 3002 } else if (!wname || !Nname) { 3003 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF), 3004 basename(argv[0])); 3005 return (1); 3006 } 3007 } 3008 3009 if ((var = argc - optind) == 0) { 3010 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF), 3011 basename(argv[0])); 3012 return (1); 3013 } 3014 3015 /* 3016 * If the -C option is used by itself, report an error since the option 3017 * has no use without other symbol name generating options. 3018 * 3019 * If the -l option is used by itself, report an error. 3020 */ 3021 if ((flags == FLG_DEMANGLE) || (flags == FLG_LONGNAME) || 3022 (flags == (FLG_DEMANGLE | FLG_LONGNAME))) { 3023 if (flags & FLG_DEMANGLE) 3024 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DEMANGLE)); 3025 if (flags & FLG_LONGNAME) 3026 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_LONGNAME)); 3027 return (1); 3028 } 3029 3030 /* 3031 * If the -l/-C option is specified, set up the liblddbg.so. 3032 */ 3033 if (flags & FLG_LONGNAME) 3034 dbg_flags = DBG_LONG; 3035 if (flags & FLG_DEMANGLE) 3036 dbg_flags |= DBG_DEMANGLE; 3037 if (dbg_flags) 3038 Dbg_set(dbg_flags); 3039 3040 /* 3041 * If the -w option has indicated an output file open it. It's 3042 * arguable whether this option has much use when multiple files are 3043 * being processed. 3044 */ 3045 if (wname) { 3046 if ((wfd = open(wname, (O_RDWR | O_CREAT | O_TRUNC), 3047 0666)) < 0) { 3048 int err = errno; 3049 (void) fprintf(stderr, MSG_INTL(MSG_ERR_OPEN), 3050 wname, strerror(err)); 3051 (void) fflush(stderr); 3052 wfd = 0; 3053 } 3054 } 3055 3056 /* 3057 * Open the input file and initialize the elf interface. 3058 */ 3059 for (; optind < argc; optind++) { 3060 const char *file = argv[optind]; 3061 3062 if ((fd = open(argv[optind], O_RDONLY)) == -1) { 3063 int err = errno; 3064 (void) fprintf(stderr, MSG_INTL(MSG_ERR_OPEN), 3065 file, strerror(err)); 3066 (void) fflush(stderr); 3067 continue; 3068 } 3069 (void) elf_version(EV_CURRENT); 3070 if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { 3071 failure(file, MSG_ORIG(MSG_ELF_BEGIN)); 3072 (void) close(fd); 3073 continue; 3074 } 3075 3076 if (var > 1) 3077 dbg_print(MSG_ORIG(MSG_FMT_NLSTRNL), file); 3078 3079 switch (elf_kind(elf)) { 3080 case ELF_K_AR: 3081 archive(file, fd, elf, flags, Nname, wfd); 3082 break; 3083 case ELF_K_ELF: 3084 regular(file, elf, flags, Nname, wfd); 3085 break; 3086 default: 3087 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADFILE), file); 3088 (void) fflush(stderr); 3089 break; 3090 } 3091 3092 (void) close(fd); 3093 (void) elf_end(elf); 3094 } 3095 3096 if (wfd) 3097 (void) close(wfd); 3098 return (0); 3099 } 3100