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 2005 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_Word phnum, 313 GElf_Ehdr *ehdr, 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_Word phnum, GElf_Ehdr *ehdr, 358 const char *name, 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 < 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_Word phnum, 665 GElf_Ehdr *ehdr, 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 < 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_Word phnum, 767 GElf_Ehdr *ehdr, 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 < 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_Word phnum, GElf_Ehdr *ehdr, 1155 const char *name, 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_Word phnum, GElf_Ehdr *ehdr, 1375 const char *name, 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_Word phnum, GElf_Ehdr *ehdr, 2285 const char *file) 2286 { 2287 Cache *gotcache = 0, *symtab = 0, *_cache; 2288 GElf_Addr gotbgn, gotend; 2289 GElf_Shdr *gotshdr; 2290 GElf_Word cnt, gotents, gotndx; 2291 size_t gentsize; 2292 Got_info *gottable; 2293 char *gotdata; 2294 GElf_Sym gsym; 2295 GElf_Xword gsymaddr; 2296 2297 /* 2298 * First we find the got 2299 */ 2300 for (cnt = 1; cnt < shnum; cnt++) { 2301 _cache = &cache[cnt]; 2302 if (strncmp(_cache->c_name, MSG_ORIG(MSG_ELF_GOT), 4) == 0) { 2303 gotcache = _cache; 2304 break; 2305 } 2306 } 2307 if (!gotcache) 2308 return; 2309 gotshdr = &gotcache->c_shdr; 2310 gotbgn = gotshdr->sh_addr; 2311 2312 if (gotshdr->sh_size == 0) { 2313 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 2314 file, gotcache->c_name); 2315 (void) fflush(stderr); 2316 return; 2317 } 2318 gotend = gotbgn + gotshdr->sh_size; 2319 2320 /* 2321 * Some architectures don't properly set the sh_entsize 2322 * for the GOT table. If it's not set we will default 2323 * to a size of a pointer. 2324 */ 2325 if ((gentsize = gotshdr->sh_entsize) == 0) { 2326 if (ehdr->e_ident[EI_CLASS] == ELFCLASS64) 2327 gentsize = sizeof (GElf_Xword); 2328 else 2329 gentsize = sizeof (GElf_Word); 2330 } 2331 /* LINTED */ 2332 gotents = (GElf_Word)(gotshdr->sh_size / gentsize); 2333 gotdata = gotcache->c_data->d_buf; 2334 2335 if ((gottable = calloc(gotents, sizeof (Got_info))) == 0) { 2336 int err = errno; 2337 (void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC), 2338 file, strerror(err)); 2339 (void) fflush(stderr); 2340 return; 2341 } 2342 2343 /* 2344 * Now we scan through all the sections looking for any relocations 2345 * that may be against the GOT. Since these may not be isolated to a 2346 * .rel[a].got section we check them all. 2347 * While scanning sections save the symbol table entry (a symtab 2348 * overriding a dynsym) so that we can lookup _GLOBAL_OFFSET_TABLE_. 2349 */ 2350 for (cnt = 1; cnt < shnum; cnt++) { 2351 GElf_Shdr *shdr; 2352 GElf_Word rtype; 2353 Elf_Data *dsyms, *reldata; 2354 GElf_Rela rela; 2355 ulong_t rcount; 2356 int ndx; 2357 char *sname; 2358 2359 _cache = &cache[cnt]; 2360 shdr = &_cache->c_shdr; 2361 2362 if ((symtab == 0) && (shdr->sh_type == SHT_DYNSYM)) { 2363 symtab = _cache; 2364 continue; 2365 } 2366 if (shdr->sh_type == SHT_SYMTAB) { 2367 symtab = _cache; 2368 continue; 2369 } 2370 2371 rtype = shdr->sh_type; 2372 if ((rtype != SHT_RELA) && (rtype != SHT_REL)) 2373 continue; 2374 2375 /* 2376 * Determine the relocation data and number. 2377 */ 2378 if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) { 2379 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 2380 file, _cache->c_name); 2381 (void) fflush(stderr); 2382 continue; 2383 } 2384 rcount = shdr->sh_size / shdr->sh_entsize; 2385 2386 reldata = _cache->c_data; 2387 2388 /* 2389 * Get the data buffer for the associated symbol table. 2390 */ 2391 if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) { 2392 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 2393 file, _cache->c_name, EC_XWORD(shdr->sh_link)); 2394 (void) fflush(stderr); 2395 continue; 2396 } 2397 dsyms = cache[shdr->sh_link].c_data; 2398 if (dsyms->d_buf == 0) { 2399 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ), 2400 file, cache[shdr->sh_link].c_name); 2401 (void) fflush(stderr); 2402 continue; 2403 } 2404 2405 sname = cache[shdr->sh_link].c_name; 2406 shdr = &cache[shdr->sh_link].c_shdr; 2407 /* 2408 * Get the associated string table section. 2409 */ 2410 if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) { 2411 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK), 2412 file, sname, EC_XWORD(shdr->sh_link)); 2413 (void) fflush(stderr); 2414 continue; 2415 } 2416 2417 /* LINTED */ 2418 for (ndx = 0; ndx < rcount; ++ndx) { 2419 GElf_Sym _sym; 2420 GElf_Word sndx; 2421 GElf_Addr offset; 2422 Got_info *gip; 2423 void *relret; 2424 2425 if (rtype == SHT_RELA) { 2426 relret = (void *)gelf_getrela(reldata, ndx, 2427 &rela); 2428 } else { 2429 relret = (void *)gelf_getrel(reldata, ndx, 2430 (GElf_Rel *)&rela); 2431 } 2432 if (relret == NULL) { 2433 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADREL), 2434 file, _cache->c_name, elf_errmsg(0)); 2435 (void) fflush(stderr); 2436 break; 2437 } 2438 2439 offset = rela.r_offset; 2440 /* LINTED */ 2441 sndx = (GElf_Word)GELF_R_SYM(rela.r_info); 2442 2443 /* 2444 * Only pay attention to relocations against the GOT. 2445 */ 2446 if ((offset < gotbgn) || (offset > gotend)) 2447 continue; 2448 2449 /* LINTED */ 2450 gotndx = (GElf_Word)((offset - gotbgn) / 2451 gotshdr->sh_entsize); 2452 gip = &gottable[gotndx]; 2453 if (gip->g_rshtype != 0) { 2454 (void) fprintf(stderr, 2455 MSG_INTL(MSG_GOT_MULTIPLE), file, 2456 /* LINTED */ 2457 EC_WORD(gotndx), EC_XWORD(offset)); 2458 (void) fflush(stderr); 2459 continue; 2460 } 2461 2462 /* LINTED */ 2463 if (gelf_getsym(dsyms, sndx, &_sym) == NULL) { 2464 (void) fprintf(stderr, 2465 MSG_INTL(MSG_ERR_RELBADSYMNDX), 2466 file, elf_errmsg(0)); 2467 (void) fflush(stderr); 2468 gip->g_symname = MSG_INTL(MSG_STR_UNKNOWN); 2469 } else { 2470 gip->g_symname = string(_cache, sndx, 2471 &cache[shdr->sh_link], file, _sym.st_name); 2472 } 2473 gip->g_rshtype = rtype; 2474 gip->g_rela = rela; 2475 } 2476 } 2477 2478 if (symlookup(MSG_ORIG(MSG_GOT_SYM), cache, shnum, &gsym, symtab, file)) 2479 gsymaddr = gsym.st_value; 2480 else 2481 gsymaddr = gotbgn; 2482 2483 dbg_print(MSG_ORIG(MSG_STR_EMPTY)); 2484 dbg_print(MSG_INTL(MSG_ELF_SCN_GOT), gotcache->c_name, gotents); 2485 Gelf_got_title(ehdr->e_ident[EI_CLASS]); 2486 2487 for (gotndx = 0; gotndx < gotents; gotndx++) { 2488 Got_info *gip; 2489 Sword gindex; 2490 GElf_Addr gaddr; 2491 GElf_Xword gotentry; 2492 2493 gip = &gottable[gotndx]; 2494 2495 gaddr = gotbgn + (gotndx * gentsize); 2496 /* LINTED */ 2497 gindex = (Sword)((gaddr - gsymaddr) / gentsize); 2498 2499 if (gentsize == sizeof (GElf_Word)) 2500 /* LINTED */ 2501 gotentry = (GElf_Xword)(*((GElf_Word *)(gotdata) + 2502 gotndx)); 2503 else 2504 /* LINTED */ 2505 gotentry = *((GElf_Xword *)(gotdata) + gotndx); 2506 2507 Gelf_got_entry(ehdr, gindex, gaddr, gotentry, gip->g_rshtype, 2508 &gip->g_rela, gip->g_symname); 2509 } 2510 2511 free(gottable); 2512 } 2513 2514 void 2515 checksum(Elf *elf) 2516 { 2517 dbg_print(MSG_ORIG(MSG_STR_EMPTY)); 2518 dbg_print(MSG_INTL(MSG_STR_CHECKSUM), gelf_checksum(elf)); 2519 } 2520 2521 static void 2522 regular(const char *file, Elf *elf, uint32_t flags, char *Nname, int wfd) 2523 { 2524 Elf_Scn *scn; 2525 GElf_Ehdr ehdr; 2526 Elf_Data *data; 2527 uint_t cnt; 2528 GElf_Word shnum, phnum; 2529 size_t shstrndx, _shnum, _phnum; 2530 GElf_Shdr nameshdr; 2531 GElf_Shdr shdr0; 2532 GElf_Shdr *_shdr0; 2533 char *names = 0; 2534 Cache *cache, *_cache; 2535 Cache *versymcache; 2536 2537 if (gelf_getehdr(elf, &ehdr) == NULL) { 2538 failure(file, MSG_ORIG(MSG_ELF_GETEHDR)); 2539 return; 2540 } 2541 2542 if (elf_getshnum(elf, &_shnum) == 0) { 2543 failure(file, MSG_ORIG(MSG_ELF_GETSHNUM)); 2544 return; 2545 } 2546 /* LINTED */ 2547 shnum = (GElf_Word)_shnum; 2548 2549 if (elf_getshstrndx(elf, &shstrndx) == 0) { 2550 failure(file, MSG_ORIG(MSG_ELF_GETSHSTRNDX)); 2551 return; 2552 } 2553 2554 if (elf_getphnum(elf, &_phnum) == 0) { 2555 failure(file, MSG_ORIG(MSG_ELF_GETPHNUM)); 2556 return; 2557 } 2558 /* LINTED */ 2559 phnum = (GElf_Word)_phnum; 2560 2561 if ((scn = elf_getscn(elf, 0)) != NULL) { 2562 if ((_shdr0 = gelf_getshdr(scn, &shdr0)) == NULL) { 2563 failure(file, MSG_ORIG(MSG_ELF_GETSHDR)); 2564 (void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SCN), 0); 2565 (void) fflush(stderr); 2566 return; 2567 } 2568 } else 2569 _shdr0 = 0; 2570 2571 /* 2572 * Print the elf header. 2573 */ 2574 if (flags & FLG_EHDR) 2575 Gelf_elf_header(&ehdr, _shdr0); 2576 2577 /* 2578 * Print the program headers. 2579 */ 2580 if ((flags & FLG_PHDR) && phnum != 0) { 2581 GElf_Phdr phdr; 2582 2583 for (cnt = 0; cnt < phnum; cnt++) { 2584 if (gelf_getphdr(elf, cnt, &phdr) == NULL) { 2585 failure(file, MSG_ORIG(MSG_ELF_GETPHDR)); 2586 return; 2587 } 2588 2589 dbg_print(MSG_ORIG(MSG_STR_EMPTY)); 2590 dbg_print(MSG_INTL(MSG_ELF_PHDR), cnt); 2591 Gelf_phdr_entry(ehdr.e_machine, &phdr); 2592 } 2593 } 2594 2595 2596 /* 2597 * Return now if there are no section, if there's just one section to 2598 * act as an extension of the ELF header, or if on section information 2599 * was requested. 2600 */ 2601 if ((shnum <= 1) || (flags && (flags & ~(FLG_EHDR | FLG_PHDR)) == 0)) { 2602 if ((ehdr.e_type == ET_CORE) && (flags & FLG_NOTE)) 2603 note(0, shnum, 0, file); 2604 return; 2605 } 2606 2607 /* 2608 * Obtain the .shstrtab data buffer to provide the required section 2609 * name strings. 2610 */ 2611 if ((scn = elf_getscn(elf, shstrndx)) == NULL) { 2612 failure(file, MSG_ORIG(MSG_ELF_GETSCN)); 2613 (void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SHDR), 2614 EC_XWORD(shstrndx)); 2615 (void) fflush(stderr); 2616 } else if ((data = elf_getdata(scn, NULL)) == NULL) { 2617 failure(file, MSG_ORIG(MSG_ELF_GETDATA)); 2618 (void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_DATA), 2619 EC_XWORD(shstrndx)); 2620 (void) fflush(stderr); 2621 } else if (gelf_getshdr(scn, &nameshdr) == NULL) { 2622 failure(file, MSG_ORIG(MSG_ELF_GETSHDR)); 2623 (void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SCN), 2624 /* LINTED */ 2625 (int)elf_ndxscn(scn)); 2626 (void) fflush(stderr); 2627 } else if ((names = data->d_buf) == 0) { 2628 (void) fprintf(stderr, MSG_INTL(MSG_ERR_SHSTRNULL), file); 2629 (void) fflush(stderr); 2630 } 2631 2632 /* 2633 * Fill in the cache descriptor with information for each section. 2634 */ 2635 if ((cache = malloc(shnum * sizeof (Cache))) == 0) { 2636 int err = errno; 2637 (void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC), 2638 file, strerror(err)); 2639 (void) fflush(stderr); 2640 return; 2641 } 2642 2643 *cache = _cache_init; 2644 _cache = cache; 2645 _cache++; 2646 2647 for (cnt = 1, scn = NULL; scn = elf_nextscn(elf, scn); 2648 cnt++, _cache++) { 2649 if (gelf_getshdr(scn, &_cache->c_shdr) == NULL) { 2650 failure(file, MSG_ORIG(MSG_ELF_GETSHDR)); 2651 (void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SCN), 2652 /* LINTED */ 2653 (int)elf_ndxscn(scn)); 2654 (void) fflush(stderr); 2655 } 2656 2657 if (names && _cache->c_shdr.sh_name && 2658 /* LINTED */ 2659 (nameshdr.sh_size > _cache->c_shdr.sh_name)) 2660 _cache->c_name = names + _cache->c_shdr.sh_name; 2661 else { 2662 /* 2663 * If there exists no shstrtab data, or a section header 2664 * has no name (an invalid index of 0), then compose a 2665 * name for each section. 2666 */ 2667 char scnndxnm[100]; 2668 2669 (void) snprintf(scnndxnm, 100, MSG_INTL(MSG_FMT_SCNNDX), 2670 cnt); 2671 2672 /* 2673 * Although we have a valid shstrtab section inform the 2674 * user if this section name index exceeds the shstrtab 2675 * data. 2676 */ 2677 if (names && 2678 /* LINTED */ 2679 (nameshdr.sh_size <= _cache->c_shdr.sh_name)) { 2680 (void) fprintf(stderr, 2681 MSG_INTL(MSG_ERR_BADSHNAME), file, 2682 _cache->c_name, 2683 EC_XWORD(_cache->c_shdr.sh_name)); 2684 (void) fflush(stderr); 2685 } 2686 2687 if ((_cache->c_name = 2688 malloc(strlen(scnndxnm) + 1)) == 0) { 2689 int err = errno; 2690 (void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC), 2691 file, strerror(err)); 2692 (void) fflush(stderr); 2693 return; 2694 } 2695 (void) strcpy(_cache->c_name, scnndxnm); 2696 } 2697 2698 if ((_cache->c_data = elf_getdata(scn, NULL)) == NULL) { 2699 failure(file, MSG_ORIG(MSG_ELF_GETDATA)); 2700 (void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SCNDATA), 2701 /* LINTED */ 2702 (int)elf_ndxscn(scn)); 2703 (void) fflush(stderr); 2704 } 2705 2706 /* 2707 * Do we wish to write the section out? 2708 */ 2709 if (wfd && Nname && (strcmp(Nname, _cache->c_name) == 0)) { 2710 (void) write(wfd, _cache->c_data->d_buf, 2711 _cache->c_data->d_size); 2712 } 2713 } 2714 2715 if (flags & FLG_SHDR) 2716 sections(file, cache, shnum, phnum, &ehdr, Nname); 2717 2718 if (flags & FLG_INTERP) 2719 interp(file, cache, shnum, phnum, &ehdr, elf); 2720 2721 versymcache = versions(cache, shnum, file, flags); 2722 2723 if (flags & FLG_SYMBOLS) 2724 symbols(cache, shnum, phnum, &ehdr, Nname, versymcache, file); 2725 2726 if (flags & FLG_HASH) 2727 hash(cache, shnum, Nname, file, flags); 2728 2729 if (flags & FLG_GOT) 2730 got(cache, shnum, phnum, &ehdr, file); 2731 2732 if (flags & FLG_GROUP) 2733 group(cache, shnum, Nname, file, flags); 2734 2735 if (flags & FLG_SYMINFO) 2736 syminfo(cache, shnum, file); 2737 2738 if (flags & FLG_RELOC) 2739 reloc(cache, shnum, phnum, &ehdr, Nname, file, flags); 2740 2741 if (flags & FLG_DYNAMIC) 2742 dynamic(cache, shnum, &ehdr, file); 2743 2744 if (flags & FLG_NOTE) 2745 note(cache, shnum, Nname, file); 2746 2747 if (flags & FLG_MOVE) 2748 move(cache, shnum, Nname, file, flags); 2749 2750 if (flags & FLG_CHECKSUM) 2751 checksum(elf); 2752 2753 if (flags & FLG_CAP) 2754 cap(file, cache, shnum, phnum, &ehdr, elf); 2755 2756 if (flags & FLG_UNWIND) 2757 unwind(cache, shnum, phnum, &ehdr, Nname, file, elf); 2758 2759 free(cache); 2760 } 2761 2762 static void 2763 archive(const char *file, int fd, Elf *elf, uint32_t flags, char *Nname, 2764 int wfd) 2765 { 2766 Elf_Cmd cmd = ELF_C_READ; 2767 Elf_Arhdr *arhdr; 2768 Elf *_elf = 0; 2769 size_t ptr; 2770 Elf_Arsym *arsym = 0; 2771 2772 /* 2773 * Determine if the archive sysmbol table itself is required. 2774 */ 2775 if ((flags & FLG_SYMBOLS) && ((Nname == NULL) || 2776 (strcmp(Nname, MSG_ORIG(MSG_ELF_ARSYM)) == 0))) { 2777 /* 2778 * Get the archive symbol table. 2779 */ 2780 if (((arsym = elf_getarsym(elf, &ptr)) == 0) && elf_errno()) { 2781 /* 2782 * The arsym could be 0 even though there was no error. 2783 * Print the error message only when there was 2784 * real error from elf_getarsym(). 2785 */ 2786 failure(file, MSG_ORIG(MSG_ELF_GETARSYM)); 2787 return; 2788 } 2789 } 2790 2791 /* 2792 * Print the archive symbol table only when the archive symbol 2793 * table exists and it was requested to print. 2794 */ 2795 if (arsym) { 2796 size_t cnt; 2797 char index[MAXNDXSIZE]; 2798 size_t offset = 0, _offset = 0; 2799 2800 /* 2801 * Print out all the symbol entries. 2802 */ 2803 dbg_print(MSG_INTL(MSG_ARCHIVE_SYMTAB)); 2804 dbg_print(MSG_INTL(MSG_ARCHIVE_FIELDS)); 2805 2806 for (cnt = 0; cnt < ptr; cnt++, arsym++) { 2807 /* 2808 * For each object obtain an elf descriptor so that we 2809 * can establish the members name. Note, we have had 2810 * archives where the archive header has not been 2811 * obtainable so be lenient with errors. 2812 */ 2813 if ((offset == 0) || ((arsym->as_off != 0) && 2814 (arsym->as_off != _offset))) { 2815 2816 if (_elf) 2817 (void) elf_end(_elf); 2818 2819 if (elf_rand(elf, arsym->as_off) != 2820 arsym->as_off) { 2821 failure(file, MSG_ORIG(MSG_ELF_RAND)); 2822 arhdr = 0; 2823 } else if ((_elf = elf_begin(fd, 2824 ELF_C_READ, elf)) == 0) { 2825 failure(file, MSG_ORIG(MSG_ELF_BEGIN)); 2826 arhdr = 0; 2827 } else if ((arhdr = elf_getarhdr(_elf)) == 0) { 2828 failure(file, 2829 MSG_ORIG(MSG_ELF_GETARHDR)); 2830 arhdr = 0; 2831 } 2832 2833 _offset = arsym->as_off; 2834 if (offset == 0) 2835 offset = _offset; 2836 } 2837 2838 (void) snprintf(index, MAXNDXSIZE, 2839 MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(cnt)); 2840 if (arsym->as_off) 2841 dbg_print(MSG_ORIG(MSG_FMT_ARSYM1), index, 2842 /* LINTED */ 2843 (int)arsym->as_off, arhdr ? arhdr->ar_name : 2844 MSG_INTL(MSG_STR_UNKNOWN), (arsym->as_name ? 2845 demangle(arsym->as_name, flags) : 2846 MSG_INTL(MSG_STR_NULL))); 2847 else 2848 dbg_print(MSG_ORIG(MSG_FMT_ARSYM2), index, 2849 /* LINTED */ 2850 (int)arsym->as_off); 2851 } 2852 2853 if (_elf) 2854 (void) elf_end(_elf); 2855 2856 /* 2857 * If we only need the archive symbol table return. 2858 */ 2859 if ((flags & FLG_SYMBOLS) && Nname && 2860 (strcmp(Nname, MSG_ORIG(MSG_ELF_ARSYM)) == 0)) 2861 return; 2862 2863 /* 2864 * Reset elf descriptor in preparation for processing each 2865 * member. 2866 */ 2867 if (offset) 2868 (void) elf_rand(elf, offset); 2869 } 2870 2871 /* 2872 * Process each object within the archive. 2873 */ 2874 while ((_elf = elf_begin(fd, cmd, elf)) != NULL) { 2875 char name[MAXPATHLEN]; 2876 2877 if ((arhdr = elf_getarhdr(_elf)) == NULL) { 2878 failure(file, MSG_ORIG(MSG_ELF_GETARHDR)); 2879 return; 2880 } 2881 if (*arhdr->ar_name != '/') { 2882 (void) snprintf(name, MAXPATHLEN, 2883 MSG_ORIG(MSG_FMT_ARNAME), file, arhdr->ar_name); 2884 dbg_print(MSG_ORIG(MSG_FMT_NLSTR), name); 2885 2886 switch (elf_kind(_elf)) { 2887 case ELF_K_AR: 2888 archive(name, fd, _elf, flags, Nname, wfd); 2889 break; 2890 case ELF_K_ELF: 2891 regular(name, _elf, flags, Nname, wfd); 2892 break; 2893 default: 2894 (void) fprintf(stderr, 2895 MSG_INTL(MSG_ERR_BADFILE), name); 2896 (void) fflush(stderr); 2897 break; 2898 } 2899 } 2900 2901 cmd = elf_next(_elf); 2902 (void) elf_end(_elf); 2903 } 2904 } 2905 2906 int 2907 main(int argc, char **argv, char **envp) 2908 { 2909 Elf *elf; 2910 int var, fd, wfd = 0; 2911 char *Nname = NULL, *wname = 0; 2912 uint32_t flags = 0, dbg_flags = 0; 2913 2914 /* 2915 * If we're on a 64-bit kernel, try to exec a full 64-bit version of 2916 * the binary. If successful, conv_check_native() won't return. 2917 */ 2918 conv_check_native(argv, envp); 2919 2920 /* 2921 * Establish locale. 2922 */ 2923 (void) setlocale(LC_MESSAGES, MSG_ORIG(MSG_STR_EMPTY)); 2924 (void) textdomain(MSG_ORIG(MSG_SUNW_OST_SGS)); 2925 2926 (void) setvbuf(stdout, NULL, _IOLBF, 0); 2927 (void) setvbuf(stderr, NULL, _IOLBF, 0); 2928 2929 opterr = 0; 2930 while ((var = getopt(argc, argv, MSG_ORIG(MSG_STR_OPTIONS))) != EOF) { 2931 switch (var) { 2932 case 'C': 2933 flags |= FLG_DEMANGLE; 2934 break; 2935 case 'c': 2936 flags |= FLG_SHDR; 2937 break; 2938 case 'd': 2939 flags |= FLG_DYNAMIC; 2940 break; 2941 case 'e': 2942 flags |= FLG_EHDR; 2943 break; 2944 case 'G': 2945 flags |= FLG_GOT; 2946 break; 2947 case 'g': 2948 flags |= FLG_GROUP; 2949 break; 2950 case 'H': 2951 flags |= FLG_CAP; 2952 break; 2953 case 'h': 2954 flags |= FLG_HASH; 2955 break; 2956 case 'i': 2957 flags |= FLG_INTERP; 2958 break; 2959 case 'k': 2960 flags |= FLG_CHECKSUM; 2961 break; 2962 case 'l': 2963 flags |= FLG_LONGNAME; 2964 break; 2965 case 'm': 2966 flags |= FLG_MOVE; 2967 break; 2968 case 'N': 2969 Nname = optarg; 2970 break; 2971 case 'n': 2972 flags |= FLG_NOTE; 2973 break; 2974 case 'p': 2975 flags |= FLG_PHDR; 2976 break; 2977 case 'r': 2978 flags |= FLG_RELOC; 2979 break; 2980 case 's': 2981 flags |= FLG_SYMBOLS; 2982 break; 2983 case 'u': 2984 flags |= FLG_UNWIND; 2985 break; 2986 case 'v': 2987 flags |= FLG_VERSIONS; 2988 break; 2989 case 'w': 2990 wname = optarg; 2991 break; 2992 case 'y': 2993 flags |= FLG_SYMINFO; 2994 break; 2995 case '?': 2996 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF), 2997 basename(argv[0])); 2998 detail_usage(); 2999 return (1); 3000 default: 3001 break; 3002 } 3003 } 3004 3005 /* 3006 * Validate any arguments. 3007 */ 3008 if (flags == 0) { 3009 if (!wname && !Nname) { 3010 flags = FLG_EVERYTHING; 3011 } else if (!wname || !Nname) { 3012 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF), 3013 basename(argv[0])); 3014 return (1); 3015 } 3016 } 3017 3018 if ((var = argc - optind) == 0) { 3019 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF), 3020 basename(argv[0])); 3021 return (1); 3022 } 3023 3024 /* 3025 * If the -C option is used by itself, report an error since the option 3026 * has no use without other symbol name generating options. 3027 * 3028 * If the -l option is used by itself, report an error. 3029 */ 3030 if ((flags == FLG_DEMANGLE) || (flags == FLG_LONGNAME) || 3031 (flags == (FLG_DEMANGLE | FLG_LONGNAME))) { 3032 if (flags & FLG_DEMANGLE) 3033 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DEMANGLE)); 3034 if (flags & FLG_LONGNAME) 3035 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_LONGNAME)); 3036 return (1); 3037 } 3038 3039 /* 3040 * If the -l/-C option is specified, set up the liblddbg.so. 3041 */ 3042 if (flags & FLG_LONGNAME) 3043 dbg_flags = DBG_LONG; 3044 if (flags & FLG_DEMANGLE) 3045 dbg_flags |= DBG_DEMANGLE; 3046 if (dbg_flags) 3047 Dbg_set(dbg_flags); 3048 3049 /* 3050 * If the -w option has indicated an output file open it. It's 3051 * arguable whether this option has much use when multiple files are 3052 * being processed. 3053 */ 3054 if (wname) { 3055 if ((wfd = open(wname, (O_RDWR | O_CREAT | O_TRUNC), 3056 0666)) < 0) { 3057 int err = errno; 3058 (void) fprintf(stderr, MSG_INTL(MSG_ERR_OPEN), 3059 wname, strerror(err)); 3060 (void) fflush(stderr); 3061 wfd = 0; 3062 } 3063 } 3064 3065 /* 3066 * Open the input file and initialize the elf interface. 3067 */ 3068 for (; optind < argc; optind++) { 3069 const char *file = argv[optind]; 3070 3071 if ((fd = open(argv[optind], O_RDONLY)) == -1) { 3072 int err = errno; 3073 (void) fprintf(stderr, MSG_INTL(MSG_ERR_OPEN), 3074 file, strerror(err)); 3075 (void) fflush(stderr); 3076 continue; 3077 } 3078 (void) elf_version(EV_CURRENT); 3079 if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { 3080 failure(file, MSG_ORIG(MSG_ELF_BEGIN)); 3081 (void) close(fd); 3082 continue; 3083 } 3084 3085 if (var > 1) 3086 dbg_print(MSG_ORIG(MSG_FMT_NLSTRNL), file); 3087 3088 switch (elf_kind(elf)) { 3089 case ELF_K_AR: 3090 archive(file, fd, elf, flags, Nname, wfd); 3091 break; 3092 case ELF_K_ELF: 3093 regular(file, elf, flags, Nname, wfd); 3094 break; 3095 default: 3096 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADFILE), file); 3097 (void) fflush(stderr); 3098 break; 3099 } 3100 3101 (void) close(fd); 3102 (void) elf_end(elf); 3103 } 3104 3105 if (wfd) 3106 (void) close(wfd); 3107 return (0); 3108 } 3109