1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * Analyze the versioning information within a file. 31 * 32 * -C demangle C++ symbol names. 33 * 34 * -d dump version definitions. 35 * 36 * -l print reduced (local) symbols. 37 * 38 * -n normalize any version definitions. 39 * 40 * -o dump output in one-line fashion (more suitable for grep'ing 41 * and diff'ing). 42 * 43 * -r dump the version requirements on library dependencies 44 * 45 * -s display the symbols associated with each version definition. 46 * 47 * -v verbose output. With the -r and -d options any WEAK attribute 48 * is displayed. With the -d option, any version inheritance, 49 * and the base version are displayed. With the -s option the 50 * version symbol is displayed. 51 * 52 * -N name only print the specifed `name'. 53 */ 54 #include <fcntl.h> 55 #include <stdio.h> 56 #include <libelf.h> 57 #include <link.h> 58 #include <stdlib.h> 59 #include <string.h> 60 #include <unistd.h> 61 #include <locale.h> 62 #include <errno.h> 63 #include <sgs.h> 64 #include <conv.h> 65 #include <gelf.h> 66 #include <debug.h> 67 #include "msg.h" 68 69 #define FLG_VER_AVAIL 0x10 70 71 typedef struct cache { 72 Elf_Scn *c_scn; 73 Elf_Data *c_data; 74 char *c_name; 75 } Cache; 76 77 typedef struct gver_desc { 78 const char *vd_name; 79 unsigned long vd_hash; 80 GElf_Half vd_ndx; 81 GElf_Half vd_flags; 82 List vd_deps; 83 } GVer_desc; 84 85 static const char *cname; 86 static int Cflag, dflag, lflag, nflag, oflag, rflag, sflag, vflag; 87 88 static const char 89 * Format_ofil = "%s -", 90 * Format_tnco = "\t%s:\n", 91 * Format_tnse = "\t%s;\n", 92 * Format_bgnl = "\t%s (%s", 93 * Format_next = ", %s", 94 * Format_weak = " [WEAK]", 95 * Format_endl = ");\n"; 96 97 #define DEF_DEFINED 1 98 #define USR_DEFINED 2 99 100 /* 101 * Determine whether a symbol name should be demangled. 102 */ 103 static const char * 104 demangle(const char *name) 105 { 106 if (Cflag) 107 return (Elf_demangle_name(name)); 108 else 109 return (name); 110 } 111 112 /* 113 * Print any reduced symbols. The convention is that reduced symbols exist as 114 * LOCL entries in the .symtab, between the FILE symbol for the output file and 115 * the first FILE symbol for any input file used to build the output file. 116 */ 117 static void 118 sym_local(Cache *cache, Cache *csym, const char *file) 119 { 120 int symn, _symn, found = 0; 121 GElf_Shdr shdr; 122 GElf_Sym sym; 123 char *strs, *local = "_LOCAL_"; 124 125 (void) gelf_getshdr(csym->c_scn, &shdr); 126 strs = (char *)cache[shdr.sh_link].c_data->d_buf; 127 /* LINTED */ 128 symn = shdr.sh_info; 129 130 /* 131 * Verify symtab[1] is the output file symbol. 132 */ 133 (void) gelf_getsym(csym->c_data, 1, &sym); 134 if (GELF_ST_TYPE(sym.st_info) != STT_FILE) { 135 (void) fprintf(stderr, MSG_INTL(MSG_VER_UNREDSYMS), cname, 136 file); 137 (void) fprintf(stderr, MSG_INTL(MSG_VER_NOTSTTFILE), 138 csym->c_name); 139 return; 140 } 141 142 /* 143 * Scan the remaining symbols until the next file symbol is found. 144 */ 145 for (_symn = 2; _symn < symn; _symn++) { 146 const char *name; 147 148 (void) gelf_getsym(csym->c_data, _symn, &sym); 149 if (GELF_ST_TYPE(sym.st_info) == STT_SECTION) 150 continue; 151 if (GELF_ST_TYPE(sym.st_info) == STT_FILE) 152 break; 153 154 /* 155 * Its possible that section symbols are followed immediately 156 * by globals. This is the case if an object (filter) is 157 * generated exclusively from mapfile symbol definitions. 158 */ 159 if (GELF_ST_BIND(sym.st_info) != STB_LOCAL) 160 break; 161 162 name = demangle(strs + sym.st_name); 163 164 if (oflag) { 165 (void) printf(Format_ofil, file); 166 (void) printf("\t%s: %s\n", local, name); 167 } else { 168 if (found == 0) { 169 found = 1; 170 (void) printf(Format_tnco, local); 171 } 172 (void) printf("\t\t%s;\n", name); 173 } 174 } 175 } 176 177 /* 178 * Print the files version needed sections. 179 */ 180 static int 181 gvers_need(Cache *cache, Cache *need, const char *file, const char *name) 182 { 183 unsigned int num, _num; 184 char *strs; 185 GElf_Verneed *vnd = need->c_data->d_buf; 186 GElf_Shdr shdr; 187 int error = 0; 188 189 (void) gelf_getshdr(need->c_scn, &shdr); 190 191 /* 192 * Verify the version revision. We only check the first version 193 * structure as it is assumed all other version structures in this 194 * data section will be of the same revision. 195 */ 196 if (vnd->vn_version > VER_DEF_CURRENT) 197 (void) fprintf(stderr, MSG_INTL(MSG_VER_HIGHREV), cname, file, 198 vnd->vn_version, VER_DEF_CURRENT); 199 200 /* 201 * Get the data buffer for the associated string table. 202 */ 203 strs = (char *)cache[shdr.sh_link].c_data->d_buf; 204 num = shdr.sh_info; 205 206 for (_num = 1; _num <= num; _num++, 207 vnd = (GElf_Verneed *)((uintptr_t)vnd + vnd->vn_next)) { 208 GElf_Vernaux *vnap = (GElf_Vernaux *) 209 ((uintptr_t)vnd + vnd->vn_aux); 210 GElf_Half cnt = vnd->vn_cnt; 211 const char *_name, * dep; 212 213 /* 214 * Obtain the version name and determine if we need to process 215 * it further. 216 */ 217 _name = (char *)(strs + vnd->vn_file); 218 if (name && (strcmp(name, _name) == 0)) 219 continue; 220 221 error = 1; 222 223 /* 224 * If one-line ouput is called for display the filename being 225 * processed. 226 */ 227 if (oflag) 228 (void) printf(Format_ofil, file); 229 230 /* 231 * Determine the version name required from this file. 232 */ 233 if (cnt--) 234 dep = (char *)(strs + vnap->vna_name); 235 else 236 dep = MSG_ORIG(MSG_STR_EMPTY); 237 238 (void) printf(Format_bgnl, _name, dep); 239 if (vflag && (vnap->vna_flags == VER_FLG_WEAK)) 240 (void) printf(Format_weak); 241 242 /* 243 * Extract any other version dependencies for this file 244 */ 245 /* CSTYLED */ 246 for (vnap = (GElf_Vernaux *)((uintptr_t)vnap + vnap->vna_next); 247 cnt; cnt--, 248 vnap = (GElf_Vernaux *)((uintptr_t)vnap + vnap->vna_next)) { 249 dep = (char *)(strs + vnap->vna_name); 250 (void) printf(Format_next, dep); 251 if (vflag && (vnap->vna_flags == VER_FLG_WEAK)) 252 (void) printf(Format_weak); 253 } 254 (void) printf(Format_endl); 255 } 256 return (error); 257 } 258 259 /* 260 * Append an item to the specified list, and return a pointer to the list 261 * node created. 262 */ 263 static Listnode * 264 list_append(List *lst, const void *item, const char *file) 265 { 266 Listnode *_lnp; 267 268 if ((_lnp = malloc(sizeof (Listnode))) == 0) { 269 int err = errno; 270 (void) fprintf(stderr, MSG_INTL(MSG_SYS_MALLOC), cname, file, 271 strerror(err)); 272 exit(1); 273 } 274 275 _lnp->data = (void *)item; 276 _lnp->next = NULL; 277 278 if (lst->head == NULL) 279 lst->tail = lst->head = _lnp; 280 else { 281 lst->tail->next = _lnp; 282 lst->tail = lst->tail->next; 283 } 284 return (_lnp); 285 } 286 287 static GVer_desc * 288 gvers_find(const char *name, unsigned long hash, List *lst) 289 { 290 Listnode *lnp; 291 GVer_desc *vdp; 292 293 for (LIST_TRAVERSE(lst, lnp, vdp)) { 294 if (vdp->vd_hash != hash) 295 continue; 296 if (strcmp(vdp->vd_name, name) == 0) 297 return (vdp); 298 } 299 return (0); 300 } 301 302 static GVer_desc * 303 gvers_desc(const char *name, unsigned long hash, List *lst, const char *file) 304 { 305 GVer_desc *vdp; 306 307 if ((vdp = gvers_find(name, hash, lst)) == 0) { 308 if ((vdp = calloc(sizeof (GVer_desc), 1)) == 0) { 309 int err = errno; 310 (void) fprintf(stderr, MSG_INTL(MSG_SYS_MALLOC), cname, 311 file, strerror(err)); 312 exit(1); 313 } 314 315 vdp->vd_name = name; 316 vdp->vd_hash = hash; 317 318 if (list_append(lst, vdp, file) == 0) 319 return (0); 320 } 321 return (vdp); 322 } 323 324 static GVer_desc * 325 gvers_depend(const char *name, unsigned long hash, GVer_desc *vdp, List *lst, 326 const char *file) 327 { 328 GVer_desc *_vdp; 329 330 if ((_vdp = gvers_desc(name, hash, lst, file)) == 0) 331 return (0); 332 333 if (list_append(&vdp->vd_deps, _vdp, file) == 0) 334 return (0); 335 336 return (vdp); 337 } 338 339 static void 340 gvers_syms(GElf_Versym *vsp, Elf_Data *sym_data, int symn, char *strs, 341 GVer_desc *vdp, const char *file) 342 { 343 GElf_Sym sym; 344 int _symn; 345 346 for (_symn = 0; _symn < symn; _symn++) { 347 size_t size = 0; 348 const char *name; 349 350 if (vsp[_symn] != vdp->vd_ndx) 351 continue; 352 353 /* 354 * For data symbols determine the size. 355 */ 356 (void) gelf_getsym(sym_data, _symn, &sym); 357 if ((GELF_ST_TYPE(sym.st_info) == STT_OBJECT) || 358 (GELF_ST_TYPE(sym.st_info) == STT_COMMON) || 359 (GELF_ST_TYPE(sym.st_info) == STT_TLS)) 360 size = (size_t)sym.st_size; 361 362 name = demangle(strs + sym.st_name); 363 364 /* 365 * Only output the version symbol when the verbose flag is used. 366 */ 367 if (!vflag && (sym.st_shndx == SHN_ABS)) { 368 if (strcmp(name, vdp->vd_name) == 0) 369 continue; 370 } 371 372 if (oflag) { 373 (void) printf(Format_ofil, file); 374 (void) printf("\t%s: ", vdp->vd_name); 375 if (size) 376 (void) printf("%s (%ld);\n", name, 377 (ulong_t)size); 378 else 379 (void) printf("%s;\n", name); 380 } else { 381 if (size) 382 (void) printf("\t\t%s (%ld);\n", name, 383 (ulong_t)size); 384 else 385 (void) printf("\t\t%s;\n", name); 386 } 387 } 388 } 389 390 static void 391 gvers_derefer(GVer_desc * vdp, int weak) 392 { 393 Listnode * _lnp; 394 GVer_desc * _vdp; 395 396 /* 397 * If the head of the list was a weak then we only clear out 398 * weak dependencies, but if the head of the list was 'strong' 399 * we clear the REFER bit on all dependencies. 400 */ 401 if ((weak && (vdp->vd_flags & VER_FLG_WEAK)) || (!weak)) 402 vdp->vd_flags &= ~FLG_VER_AVAIL; 403 404 for (LIST_TRAVERSE(&vdp->vd_deps, _lnp, _vdp)) 405 gvers_derefer(_vdp, weak); 406 } 407 408 409 static void 410 recurse_syms(GElf_Versym *vsp, Elf_Data *sym_data, int symn, char *strs, 411 GVer_desc *vdp, const char *file) 412 { 413 Listnode *_lnp; 414 GVer_desc *_vdp; 415 416 for (LIST_TRAVERSE(&vdp->vd_deps, _lnp, _vdp)) { 417 if (!oflag) 418 (void) printf(Format_tnco, _vdp->vd_name); 419 gvers_syms(vsp, sym_data, symn, strs, _vdp, file); 420 if (_vdp->vd_deps.head) 421 recurse_syms(vsp, sym_data, symn, strs, _vdp, file); 422 } 423 } 424 425 426 /* 427 * Print the files version definition sections. 428 */ 429 static int 430 gvers_def(Cache *cache, Cache *def, Cache *csym, const char *file, 431 const char *name) 432 { 433 unsigned int num, _num; 434 char *strs; 435 GElf_Versym *vsp; 436 GElf_Verdef *vdf = def->c_data->d_buf; 437 GElf_Shdr shdr; 438 Elf_Data *sym_data; 439 int symn; 440 GVer_desc *vdp, *bvdp = 0; 441 Listnode *lnp; 442 List verdefs = {0, 0}; 443 int error = 0; 444 445 /* 446 * Verify the version revision. We only check the first version 447 * structure as it is assumed all other version structures in this 448 * data section will be of the same revision. 449 */ 450 if (vdf->vd_version > VER_DEF_CURRENT) { 451 (void) fprintf(stderr, MSG_INTL(MSG_VER_HIGHREV), cname, file, 452 vdf->vd_version, VER_DEF_CURRENT); 453 } 454 455 /* 456 * Get the data buffer for the associated string table. 457 */ 458 (void) gelf_getshdr(def->c_scn, &shdr); 459 strs = (char *)cache[shdr.sh_link].c_data->d_buf; 460 num = shdr.sh_info; 461 462 /* 463 * Process the version definitions placing each on a version dependency 464 * list. 465 */ 466 for (_num = 1; _num <= num; _num++, 467 vdf = (GElf_Verdef *)((uintptr_t)vdf + vdf->vd_next)) { 468 GElf_Half cnt = vdf->vd_cnt; 469 GElf_Half ndx = vdf->vd_ndx; 470 GElf_Verdaux *vdap = (GElf_Verdaux *)((uintptr_t)vdf + 471 vdf->vd_aux); 472 const char *_name; 473 474 /* 475 * Determine the version name and any dependencies. 476 */ 477 _name = (char *)(strs + vdap->vda_name); 478 479 if ((vdp = gvers_desc(_name, elf_hash(_name), &verdefs, 480 file)) == 0) 481 return (0); 482 vdp->vd_ndx = ndx; 483 vdp->vd_flags = vdf->vd_flags | FLG_VER_AVAIL; 484 485 vdap = (GElf_Verdaux *)((uintptr_t)vdap + vdap->vda_next); 486 for (cnt--; cnt; cnt--, 487 vdap = (GElf_Verdaux *)((uintptr_t)vdap + vdap->vda_next)) { 488 _name = (char *)(strs + vdap->vda_name); 489 if (gvers_depend(_name, elf_hash(_name), vdp, 490 &verdefs, file) == 0) 491 return (0); 492 } 493 494 /* 495 * Remember the base version for possible later use. 496 */ 497 if (ndx == VER_NDX_GLOBAL) 498 bvdp = vdp; 499 } 500 501 /* 502 * Normalize the dependency list if required. 503 */ 504 if (nflag) { 505 for (LIST_TRAVERSE(&verdefs, lnp, vdp)) { 506 Listnode * _lnp; 507 GVer_desc * _vdp; 508 int type = vdp->vd_flags & VER_FLG_WEAK; 509 510 for (LIST_TRAVERSE(&vdp->vd_deps, _lnp, _vdp)) 511 gvers_derefer(_vdp, type); 512 } 513 514 /* 515 * Always dereference the base version. 516 */ 517 if (bvdp) 518 bvdp->vd_flags &= ~FLG_VER_AVAIL; 519 } 520 521 522 /* 523 * Traverse the dependency list and print out the appropriate 524 * information. 525 */ 526 for (LIST_TRAVERSE(&verdefs, lnp, vdp)) { 527 Listnode * _lnp; 528 GVer_desc * _vdp; 529 int count; 530 531 if (name && (strcmp(name, vdp->vd_name) != 0)) 532 continue; 533 534 if (!name && !(vdp->vd_flags & FLG_VER_AVAIL)) 535 continue; 536 537 error = 1; 538 539 if (vflag) { 540 /* 541 * If the verbose flag is set determine if this version 542 * has a `weak' attribute, and print any version 543 * dependencies this version inherits. 544 */ 545 if (oflag) 546 (void) printf(Format_ofil, file); 547 (void) printf("\t%s", vdp->vd_name); 548 if (vdp->vd_flags & VER_FLG_WEAK) 549 (void) printf(Format_weak); 550 551 count = 1; 552 for (LIST_TRAVERSE(&vdp->vd_deps, _lnp, _vdp)) { 553 const char *_name = _vdp->vd_name; 554 555 if (count++ == 1) { 556 if (oflag) 557 (void) printf(": {%s", _name); 558 else if (vdp->vd_flags & VER_FLG_WEAK) 559 (void) printf(":\t{%s", _name); 560 else 561 (void) printf(": \t{%s", 562 _name); 563 } else 564 (void) printf(Format_next, _name); 565 } 566 567 if (count != 1) 568 (void) printf("}"); 569 570 if (csym && !oflag) 571 (void) printf(":\n"); 572 else 573 (void) printf(";\n"); 574 } else { 575 if (csym && !oflag) 576 (void) printf(Format_tnco, vdp->vd_name); 577 else if (!csym) { 578 if (oflag) 579 (void) printf(Format_ofil, file); 580 (void) printf(Format_tnse, vdp->vd_name); 581 } 582 } 583 584 /* 585 * If we need to print symbols get the associated symbol table. 586 */ 587 if (csym) { 588 (void) gelf_getshdr(csym->c_scn, &shdr); 589 vsp = (GElf_Versym *)csym->c_data->d_buf; 590 sym_data = cache[shdr.sh_link].c_data; 591 (void) gelf_getshdr(cache[shdr.sh_link].c_scn, &shdr); 592 /* LINTED */ 593 symn = (int)(shdr.sh_size / shdr.sh_entsize); 594 } else 595 continue; 596 597 /* 598 * If a specific version name has been specified then display 599 * any of its own symbols plus any inherited from other 600 * versions. Otherwise simply print out the symbols for this 601 * version. 602 */ 603 gvers_syms(vsp, sym_data, symn, strs, vdp, file); 604 if (name) { 605 recurse_syms(vsp, sym_data, symn, strs, vdp, file); 606 607 /* 608 * If the verbose flag is set add the base version as a 609 * dependency (unless it's the list we were asked to 610 * print in the first place). 611 */ 612 if (vflag && bvdp && strcmp(name, bvdp->vd_name)) { 613 if (!oflag) 614 (void) printf(Format_tnco, bvdp->vd_name); 615 gvers_syms(vsp, sym_data, symn, strs, bvdp, 616 file); 617 } 618 } 619 } 620 return (error); 621 } 622 623 int 624 main(int argc, char **argv, char **envp) 625 { 626 GElf_Shdr shdr; 627 Elf *elf; 628 Elf_Scn *scn; 629 Elf_Data *data; 630 GElf_Ehdr ehdr; 631 int nfile, var; 632 const char *name; 633 char *names; 634 Cache *cache, *_cache; 635 Cache *_cache_def, *_cache_need, *_cache_sym, *_cache_loc; 636 int error = 0; 637 638 /* 639 * Check for a binary that better fits this architecture. 640 */ 641 (void) conv_check_native(argv, envp); 642 643 /* 644 * Establish locale. 645 */ 646 (void) setlocale(LC_MESSAGES, MSG_ORIG(MSG_STR_EMPTY)); 647 (void) textdomain(MSG_ORIG(MSG_SUNW_OST_SGS)); 648 649 cname = argv[0]; 650 name = NULL; 651 Cflag = dflag = lflag = nflag = oflag = rflag = sflag = vflag = 0; 652 653 opterr = 0; 654 while ((var = getopt(argc, argv, "CdlnorsvN:")) != EOF) { 655 switch (var) { 656 case 'C': 657 Cflag = USR_DEFINED; 658 break; 659 case 'd': 660 dflag = USR_DEFINED; 661 break; 662 case 'l': 663 lflag = USR_DEFINED; 664 break; 665 case 'n': 666 nflag = USR_DEFINED; 667 break; 668 case 'o': 669 oflag = USR_DEFINED; 670 break; 671 case 'r': 672 rflag = USR_DEFINED; 673 break; 674 case 's': 675 sflag = USR_DEFINED; 676 break; 677 case 'v': 678 vflag = USR_DEFINED; 679 break; 680 case 'N': 681 name = optarg; 682 break; 683 case '?': 684 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF), 685 cname); 686 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL)); 687 exit(1); 688 default: 689 break; 690 } 691 } 692 693 /* 694 * No files specified on the command line? 695 */ 696 if ((nfile = argc - optind) == 0) { 697 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF), cname); 698 exit(1); 699 } 700 701 /* 702 * By default print both version definitions and needed dependencies. 703 */ 704 if ((dflag == 0) && (rflag == 0)) 705 dflag = rflag = DEF_DEFINED; 706 707 /* 708 * Open the input file and initialize the elf interface. 709 */ 710 for (; optind < argc; optind++) { 711 int derror = 0, nerror = 0, err; 712 const char *file = argv[optind]; 713 714 if ((var = open(file, O_RDONLY)) == -1) { 715 err = errno; 716 (void) fprintf(stderr, MSG_INTL(MSG_SYS_OPEN), 717 cname, file, strerror(err)); 718 error = 1; 719 continue; 720 } 721 (void) elf_version(EV_CURRENT); 722 if ((elf = elf_begin(var, ELF_C_READ, NULL)) == NULL) { 723 (void) fprintf(stderr, MSG_ORIG(MSG_ELF_BEGIN), cname, 724 file, elf_errmsg(elf_errno())); 725 error = 1; 726 (void) close(var); 727 continue; 728 } 729 if (elf_kind(elf) != ELF_K_ELF) { 730 (void) fprintf(stderr, MSG_INTL(MSG_ELF_NOTELF), cname, 731 file); 732 error = 1; 733 (void) close(var); 734 (void) elf_end(elf); 735 continue; 736 } 737 if (gelf_getehdr(elf, &ehdr) == NULL) { 738 (void) fprintf(stderr, MSG_ORIG(MSG_ELF_GETEHDR), cname, 739 file, elf_errmsg(elf_errno())); 740 error = 1; 741 (void) close(var); 742 (void) elf_end(elf); 743 continue; 744 } 745 746 /* 747 * Obtain the .shstrtab data buffer to provide the required 748 * section name strings. 749 */ 750 if ((scn = elf_getscn(elf, ehdr.e_shstrndx)) == NULL) { 751 (void) fprintf(stderr, MSG_ORIG(MSG_ELF_GETSCN), cname, 752 file, elf_errmsg(elf_errno())); 753 error = 1; 754 (void) close(var); 755 (void) elf_end(elf); 756 continue; 757 } 758 if ((data = elf_getdata(scn, NULL)) == NULL) { 759 (void) fprintf(stderr, MSG_ORIG(MSG_ELF_GETDATA), cname, 760 file, elf_errmsg(elf_errno())); 761 error = 1; 762 (void) close(var); 763 (void) elf_end(elf); 764 continue; 765 } 766 names = data->d_buf; 767 768 /* 769 * Fill in the cache descriptor with information for each 770 * section we might need. We probably only need to save 771 * read-only allocable sections as this is where the version 772 * structures and their associated symbols and strings live. 773 * However, God knows what someone can do with a mapfile, and 774 * as elf_begin has already gone through all the overhead we 775 * might as well set up the cache for every section. 776 */ 777 if ((cache = calloc(ehdr.e_shnum, sizeof (Cache))) == 0) { 778 int err = errno; 779 (void) fprintf(stderr, MSG_INTL(MSG_SYS_MALLOC), cname, 780 file, strerror(err)); 781 exit(1); 782 } 783 784 _cache_def = _cache_need = _cache_sym = _cache_loc = 0; 785 _cache = cache; 786 _cache++; 787 for (scn = NULL; scn = elf_nextscn(elf, scn); _cache++) { 788 if (gelf_getshdr(scn, &shdr) == NULL) { 789 (void) fprintf(stderr, 790 MSG_ORIG(MSG_ELF_GETSHDR), cname, file, 791 elf_errmsg(elf_errno())); 792 error = 1; 793 continue; 794 } 795 if ((_cache->c_data = elf_getdata(scn, NULL)) == 796 NULL) { 797 (void) fprintf(stderr, 798 MSG_ORIG(MSG_ELF_GETDATA), cname, file, 799 elf_errmsg(elf_errno())); 800 error = 1; 801 continue; 802 } 803 _cache->c_scn = scn; 804 _cache->c_name = names + shdr.sh_name; 805 806 /* 807 * Remember the version sections and symbol table. 808 */ 809 switch (shdr.sh_type) { 810 case SHT_SUNW_verdef: 811 if (dflag) 812 _cache_def = _cache; 813 break; 814 case SHT_SUNW_verneed: 815 if (rflag) 816 _cache_need = _cache; 817 break; 818 case SHT_SUNW_versym: 819 if (sflag) 820 _cache_sym = _cache; 821 break; 822 case SHT_SYMTAB: 823 if (lflag) 824 _cache_loc = _cache; 825 break; 826 } 827 } 828 829 /* 830 * Before printing anything out determine if any warnings are 831 * necessary. 832 */ 833 if (lflag && (_cache_loc == 0)) { 834 (void) fprintf(stderr, MSG_INTL(MSG_VER_UNREDSYMS), 835 cname, file); 836 (void) fprintf(stderr, MSG_INTL(MSG_VER_NOSYMTAB)); 837 } 838 839 /* 840 * If there is more than one input file, and we're not printing 841 * one-line output, display the filename being processed. 842 */ 843 if ((nfile > 1) && !oflag) 844 (void) printf("%s:\n", file); 845 846 /* 847 * Print the files version needed sections. 848 */ 849 if (_cache_need) 850 nerror = gvers_need(cache, _cache_need, file, name); 851 852 /* 853 * Print the files version definition sections. 854 */ 855 if (_cache_def) 856 derror = gvers_def(cache, _cache_def, _cache_sym, 857 file, name); 858 859 /* 860 * Print any local symbol reductions. 861 */ 862 if (_cache_loc) 863 sym_local(cache, _cache_loc, file); 864 865 /* 866 * Determine the error return. There are three conditions that 867 * may produce an error (a non-zero return): 868 * 869 * o if the user specified -d and no version definitions 870 * were found. 871 * 872 * o if the user specified -r and no version requirements 873 * were found. 874 * 875 * o if the user specified neither -d or -r, (thus both are 876 * enabled by default), and no version definitions or 877 * version dependencies were found. 878 */ 879 if (((dflag == USR_DEFINED) && (derror == 0)) || 880 ((rflag == USR_DEFINED) && (nerror == 0)) || 881 (rflag && dflag && (derror == 0) && (nerror == 0))) 882 error = 1; 883 884 (void) close(var); 885 (void) elf_end(elf); 886 free(cache); 887 } 888 return (error); 889 } 890 891 const char * 892 _pvs_msg(Msg mid) 893 { 894 return (gettext(MSG_ORIG(mid))); 895 } 896