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 (c) 1988 AT&T
  24  * Copyright (c) 1989 AT&T
  25  * All Rights Reserved
  26  *
  27  * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
  28  */
  29 
  30 #include <stdio.h>
  31 #include <stdlib.h>
  32 #include <unistd.h>
  33 #include <ctype.h>
  34 #include <locale.h>
  35 #include <libelf.h>
  36 #include <sys/elf_SPARC.h>
  37 
  38 
  39 /* exit return codes */
  40 #define NOARGS  1
  41 #define BADELF  2
  42 #define NOALLOC 3
  43 
  44 #include <fcntl.h>
  45 #include <sys/stat.h>
  46 #include <errno.h>
  47 #include <string.h>
  48 #include <dlfcn.h>
  49 
  50 #include "sgs.h"
  51 #include "conv.h"
  52 #include "gelf.h"
  53 
  54 typedef struct {                /* structure to translate symbol table data */
  55         int  indx;
  56         char *name;
  57         GElf_Addr value;
  58         GElf_Xword size;
  59         int type;
  60         int bind;
  61         unsigned char other;
  62         unsigned int shndx;
  63         unsigned int flags;     /* flags relevant to entry */
  64 } SYM;
  65 
  66 #define FLG_SYM_SPECSEC 0x00000001      /* reserved scn index */
  67                                         /*      (SHN_ABS, SHN_COMMON, ...) */
  68 
  69 #define UNDEFINED "U"
  70 #define BSS_GLOB  "B"
  71 #define BSS_WEAK  "B*"
  72 #define BSS_LOCL  "b"
  73 #define BSS_SECN  ".bss"
  74 #define REG_GLOB  "R"
  75 #define REG_WEAK  "R*"
  76 #define REG_LOCL  "r"
  77 
  78 #define OPTSTR  ":APDoxhvnursplLCVefgRTt:" /* option string for getopt() */
  79 
  80 #define DATESIZE 60
  81 
  82 #define TYPE 7
  83 #define BIND 3
  84 
  85 #define DEF_MAX_SYM_SIZE 256
  86 
  87 static char *key[TYPE][BIND];
  88 
  89 /*
  90  * Format type used for printing value and size items.
  91  * The non-negative values here are used as array indices into
  92  * several arrays found below. Renumbering, or adding items,
  93  * will require changes to those arrays as well.
  94  */
  95 typedef enum {
  96         FMT_T_NONE = -1,        /* No format type yet assigned */
  97 
  98         /* The following are used as array indices */
  99         FMT_T_DEC = 0,
 100         FMT_T_HEX = 1,
 101         FMT_T_OCT = 2
 102 } FMT_T;
 103 
 104 /*
 105  * Determine whether a proposed format type is compatible with the current
 106  * setting. We allow setting the format as long as it hasn't already
 107  * been done, or if the new setting is the same as the current one.
 108  */
 109 #define COMPAT_FMT_FLAG(new_fmt_flag) \
 110         (fmt_flag == FMT_T_NONE) || (fmt_flag == new_fmt_flag)
 111 
 112 static FMT_T fmt_flag = FMT_T_NONE;     /* format style to use for value/size */
 113 
 114 static  int     /* flags: ?_flag corresponds to ? option */
 115         h_flag = 0,     /* suppress printing of headings */
 116         v_flag = 0,     /* sort external symbols by value */
 117         n_flag = 0,     /* sort external symbols by name */
 118         u_flag = 0,     /* print only undefined symbols */
 119         r_flag = 0,     /* prepend object file or archive name */
 120                         /* to each symbol name */
 121         R_flag = 0,     /* if "-R" issued then prepend archive name, */
 122                         /* object file name to each symbol */
 123         s_flag = 0,     /* print section name instead of section index */
 124         p_flag = 0,     /* produce terse output */
 125         P_flag = 0,     /* Portable format output */
 126         l_flag = 0,     /* produce long listing of output */
 127         L_flag = 0,     /* print SUNW_LDYNSYM instead of SYMTAB */
 128         D_flag = 0,     /* print DYNSYM instead of SYMTAB */
 129         C_flag = 0,     /* print decoded C++ names */
 130         A_flag = 0,     /* File name */
 131         e_flag = 0,     /* -e flag */
 132         g_flag = 0,     /* -g flag */
 133         V_flag = 0;     /* print version information */
 134 static char A_header[DEF_MAX_SYM_SIZE+1] = {0};
 135 
 136 static char *prog_name;
 137 static char *archive_name = (char *)0;
 138 static int errflag = 0;
 139 static void usage();
 140 static void each_file(char *);
 141 static void process(Elf *, char *);
 142 static Elf_Scn * get_scnfd(Elf *, int, int);
 143 static void get_symtab(Elf *, char *);
 144 static SYM * readsyms(Elf_Data *, GElf_Sxword, Elf *, unsigned int,
 145                         unsigned int);
 146 static int compare(SYM *, SYM *);
 147 static char *lookup(int, int);
 148 static int  is_bss_section(unsigned int, Elf *, unsigned int);
 149 static void print_ar_files(int, Elf *, char *);
 150 static void print_symtab(Elf *, unsigned int, Elf_Scn *, GElf_Shdr *, char *);
 151 static void parsename(char *);
 152 static void parse_fn_and_print(const char *, char *);
 153 static char d_buf[512];
 154 static char p_buf[512];
 155 static int exotic(const char *s);
 156 static void set_A_header(char *);
 157 static char *FormatName(char *, const char *);
 158 
 159 
 160 
 161 /*
 162  * Parses the command line options and then
 163  * calls each_file() to process each file.
 164  */
 165 int
 166 main(int argc, char *argv[], char *envp[])
 167 {
 168         char    *optstr = OPTSTR; /* option string used by getopt() */
 169         int     optchar;
 170         FMT_T   new_fmt_flag;
 171 
 172 #ifndef XPG4
 173         /*
 174          * Check for a binary that better fits this architecture.
 175          */
 176         (void) conv_check_native(argv, envp);
 177 #endif
 178 
 179         /* table of keyletters for use with -p and -P options */
 180         key[STT_NOTYPE][STB_LOCAL] = "n";
 181         key[STT_NOTYPE][STB_GLOBAL] = "N";
 182         key[STT_NOTYPE][STB_WEAK] = "N*";
 183         key[STT_OBJECT][STB_LOCAL] = "d";
 184         key[STT_OBJECT][STB_GLOBAL] = "D";
 185         key[STT_OBJECT][STB_WEAK] = "D*";
 186         key[STT_FUNC][STB_LOCAL] = "t";
 187         key[STT_FUNC][STB_GLOBAL] = "T";
 188         key[STT_FUNC][STB_WEAK] = "T*";
 189         key[STT_SECTION][STB_LOCAL] = "s";
 190         key[STT_SECTION][STB_GLOBAL] = "S";
 191         key[STT_SECTION][STB_WEAK] = "S*";
 192         key[STT_FILE][STB_LOCAL] = "f";
 193         key[STT_FILE][STB_GLOBAL] = "F";
 194         key[STT_FILE][STB_WEAK] = "F*";
 195         key[STT_COMMON][STB_LOCAL] = "c";
 196         key[STT_COMMON][STB_GLOBAL] = "C";
 197         key[STT_COMMON][STB_WEAK] = "C*";
 198         key[STT_TLS][STB_LOCAL] = "l";
 199         key[STT_TLS][STB_GLOBAL] = "L";
 200         key[STT_TLS][STB_WEAK] = "L*";
 201 
 202         prog_name = argv[0];
 203 
 204         (void) setlocale(LC_ALL, "");
 205 #if !defined(TEXT_DOMAIN)       /* Should be defined by cc -D */
 206 #define TEXT_DOMAIN "SYS_TEST"  /* Use this only if it weren't */
 207 #endif
 208         (void) textdomain(TEXT_DOMAIN);
 209 
 210         while ((optchar = getopt(argc, argv, optstr)) != -1) {
 211                 switch (optchar) {
 212                 case 'o':       if (COMPAT_FMT_FLAG(FMT_T_OCT))
 213                                         fmt_flag = FMT_T_OCT;
 214                                 else
 215                                         (void) fprintf(stderr, gettext(
 216                                             "%s: -x or -t set, -o ignored\n"),
 217                                             prog_name);
 218                                 break;
 219                 case 'x':       if (COMPAT_FMT_FLAG(FMT_T_HEX))
 220                                         fmt_flag = FMT_T_HEX;
 221                                 else
 222                                         (void) fprintf(stderr, gettext(
 223                                             "%s: -o or -t set, -x ignored\n"),
 224                                             prog_name);
 225                                 break;
 226                 case 'h':       h_flag = 1;
 227                                 break;
 228                 case 'v':       if (!n_flag)
 229                                         v_flag = 1;
 230                                 else
 231                                         (void) fprintf(stderr, gettext(
 232                                             "%s: -n set, -v ignored\n"),
 233                                             prog_name);
 234                                 break;
 235                 case 'n':       if (!v_flag)
 236                                         n_flag = 1;
 237                                 else
 238                                         (void) fprintf(stderr, gettext(
 239                                             "%s: -v set, -n ignored\n"),
 240                                             prog_name);
 241                                 break;
 242                 case 'u':       if (!e_flag && !g_flag)
 243                                         u_flag = 1;
 244                                 else
 245                                         (void) fprintf(stderr, gettext(
 246                                             "%s: -e or -g set, -u ignored\n"),
 247                                             prog_name);
 248                                 break;
 249                 case 'e':       if (!u_flag && !g_flag)
 250                                         e_flag = 1;
 251                                 else
 252                                         (void) fprintf(stderr, gettext(
 253                                             "%s: -u or -g set, -e ignored\n"),
 254                                             prog_name);
 255                                 break;
 256                 case 'g':       if (!u_flag && !e_flag)
 257                                         g_flag = 1;
 258                                 else
 259                                         (void) fprintf(stderr, gettext(
 260                                             "%s: -u or -e set, -g ignored\n"),
 261                                             prog_name);
 262                                 break;
 263                 case 'r':       if (R_flag) {
 264                                         R_flag = 0;
 265                                         (void) fprintf(stderr, gettext(
 266                                             "%s: -r set, -R ignored\n"),
 267                                             prog_name);
 268                                 }
 269                                 r_flag = 1;
 270                                 break;
 271                 case 's':       s_flag = 1;
 272                                 break;
 273                 case 'p':       if (P_flag == 1) {
 274                                         (void) fprintf(stderr, gettext(
 275                                             "nm: -P set. -p ignored\n"));
 276                                 } else
 277                                         p_flag = 1;
 278                                 break;
 279                 case 'P':       if (p_flag == 1) {
 280                                         (void) fprintf(stderr, gettext(
 281                                             "nm: -p set. -P ignored\n"));
 282                                 } else
 283                                         P_flag = 1;
 284                                 break;
 285                 case 'l':       l_flag = 1;
 286                                 break;
 287                 case 'L':       if (D_flag == 1) {
 288                                         (void) fprintf(stderr, gettext(
 289                                             "nm: -D set. -L ignored\n"));
 290                                 } else
 291                                         L_flag = 1;
 292                                 break;
 293                 case 'D':       if (L_flag == 1) {
 294                                         (void) fprintf(stderr, gettext(
 295                                             "nm: -L set. -D ignored\n"));
 296                                 } else
 297                                         D_flag = 1;
 298                                 break;
 299                 case 'C':
 300                                 C_flag = 1;
 301                                 break;
 302                 case 'A':       A_flag = 1;
 303                                 break;
 304                 case 'V':       V_flag = 1;
 305                                 (void) fprintf(stderr, "nm: %s %s\n",
 306                                     (const char *)SGU_PKG,
 307                                     (const char *)SGU_REL);
 308                                 break;
 309                 case 'f':       /* -f is a noop, see man page */
 310                                 break;
 311                 case 'R':       if (!r_flag)
 312                                         R_flag = 1;
 313                                 else
 314                                         (void) fprintf(stderr, gettext(
 315                                             "%s: -r set, -R ignored\n"),
 316                                             prog_name);
 317                                 break;
 318                 case 'T':
 319                                 break;
 320                 case 't':       if (strcmp(optarg, "o") == 0) {
 321                                         new_fmt_flag = FMT_T_OCT;
 322                                 } else if (strcmp(optarg, "d") == 0) {
 323                                         new_fmt_flag = FMT_T_DEC;
 324                                 } else if (strcmp(optarg, "x") == 0) {
 325                                         new_fmt_flag = FMT_T_HEX;
 326                                 } else {
 327                                         new_fmt_flag = FMT_T_NONE;
 328                                 }
 329                                 if (new_fmt_flag == FMT_T_NONE) {
 330                                         errflag += 1;
 331                                         (void) fprintf(stderr, gettext(
 332 "nm: -t requires radix value (d, o, x): %s\n"), optarg);
 333                                 } else if (COMPAT_FMT_FLAG(new_fmt_flag)) {
 334                                         fmt_flag = new_fmt_flag;
 335                                 } else {
 336                                         (void) fprintf(stderr, gettext(
 337                                 "nm: -t or -o or -x set. -t ignored.\n"));
 338                                 }
 339                                 break;
 340                 case ':':       errflag += 1;
 341                                 (void) fprintf(stderr, gettext(
 342                                     "nm: %c requires operand\n"), optopt);
 343                                 break;
 344                 case '?':       errflag += 1;
 345                                 break;
 346                 default:        break;
 347                 }
 348         }
 349 
 350         if (errflag || (optind >= argc)) {
 351                 if (!(V_flag && (argc == 2))) {
 352                         usage();
 353                         exit(NOARGS);
 354                 }
 355         }
 356 
 357         /*
 358          * If no explicit format style was specified, set the default
 359          * here. In general, the default is for value and size items
 360          * to be displayed in decimal format. The exception is that
 361          * the default for -P is hexidecimal.
 362          */
 363         if (fmt_flag == FMT_T_NONE)
 364                 fmt_flag = P_flag ? FMT_T_HEX : FMT_T_DEC;
 365 
 366 
 367         while (optind < argc) {
 368                 each_file(argv[optind]);
 369                 optind++;
 370         }
 371         return (errflag);
 372 }
 373 
 374 /*
 375  * Print out a usage message in short form when program is invoked
 376  * with insufficient or no arguments, and in long form when given
 377  * either a ? or an invalid option.
 378  */
 379 static void
 380 usage()
 381 {
 382         (void) fprintf(stderr, gettext(
 383 "Usage: nm [-ACDhLlnPpRrsTVv] [-efox] [-g | -u] [-t d|o|x] file ...\n"));
 384 }
 385 
 386 /*
 387  * Takes a filename as input.  Test first for a valid version
 388  * of libelf.a and exit on error.  Process each valid file
 389  * or archive given as input on the command line.  Check
 390  * for file type.  If it is an archive, call print_ar_files
 391  * to process each member of the archive in the same manner
 392  * as object files on the command line.  The same tests for
 393  * valid object file type apply to regular archive members.
 394  * If it is an ELF object file, process it; otherwise
 395  * warn that it is an invalid file type and return from
 396  * processing the file.
 397  */
 398 
 399 static void
 400 each_file(char *filename)
 401 {
 402         Elf     *elf_file;
 403         int     fd;
 404         Elf_Kind   file_type;
 405 
 406         struct stat64 buf;
 407 
 408         Elf_Cmd cmd;
 409         errno = 0;
 410         if (stat64(filename, &buf) == -1)   {
 411                 (void) fprintf(stderr, "%s: ", prog_name);
 412                 perror(filename);
 413                 errflag++;
 414                 return;
 415         }
 416         if (elf_version(EV_CURRENT) == EV_NONE) {
 417                 (void) fprintf(stderr, gettext(
 418                     "%s: %s: libelf is out of date\n"),
 419                     prog_name, filename);
 420                 exit(BADELF);
 421         }
 422 
 423         if ((fd = open((filename), O_RDONLY)) == -1) {
 424                 (void) fprintf(stderr, gettext("%s: %s: cannot read file\n"),
 425                     prog_name, filename);
 426                 errflag++;
 427                 return;
 428         }
 429         cmd = ELF_C_READ;
 430         if ((elf_file = elf_begin(fd, cmd, (Elf *) 0)) == NULL) {
 431                 (void) fprintf(stderr,
 432                     "%s: %s: %s\n", prog_name, filename, elf_errmsg(-1));
 433                 errflag++;
 434                 (void) close(fd);
 435                 return;
 436         }
 437         file_type = elf_kind(elf_file);
 438         if (file_type == ELF_K_AR) {
 439                 print_ar_files(fd, elf_file, filename);
 440         } else {
 441                 if (file_type == ELF_K_ELF) {
 442 #ifndef XPG4
 443                         if (u_flag && !h_flag) {
 444                                 /*
 445                                  * u_flag is specified.
 446                                  */
 447                                 if (p_flag)
 448                                         (void) printf("\n\n%s:\n\n", filename);
 449                                 else
 450                                         (void) printf(gettext(
 451                                 "\n\nUndefined symbols from %s:\n\n"),
 452                                             filename);
 453                         } else if (!h_flag & !P_flag)
 454 #else
 455                         if (!h_flag & !P_flag)
 456 #endif
 457                         {
 458                                 if (p_flag)
 459                                         (void) printf("\n\n%s:\n", filename);
 460                                 else {
 461                                         if (A_flag != 0)
 462                                                 (void) printf("\n\n%s%s:\n",
 463                                                     A_header, filename);
 464                                         else
 465                                                 (void) printf("\n\n%s:\n",
 466                                                     filename);
 467                                 }
 468                         }
 469                         archive_name = (char *)0;
 470                         process(elf_file, filename);
 471                 } else {
 472                         (void) fprintf(stderr, gettext(
 473                             "%s: %s: invalid file type\n"),
 474                             prog_name, filename);
 475                         errflag++;
 476                 }
 477         }
 478         (void) elf_end(elf_file);
 479         (void) close(fd);
 480 }
 481 
 482 /*
 483  * Get the ELF header and, if it exists, call get_symtab()
 484  * to begin processing of the file; otherwise, return from
 485  * processing the file with a warning.
 486  */
 487 static void
 488 process(Elf *elf_file, char *filename)
 489 {
 490         GElf_Ehdr ehdr;
 491 
 492         if (gelf_getehdr(elf_file, &ehdr) == NULL) {
 493                 (void) fprintf(stderr,
 494                     "%s: %s: %s\n", prog_name, filename, elf_errmsg(-1));
 495                 return;
 496         }
 497 
 498         set_A_header(filename);
 499         get_symtab(elf_file, filename);
 500 }
 501 
 502 /*
 503  * Get section descriptor for the associated string table
 504  * and verify that the type of the section pointed to is
 505  * indeed of type STRTAB.  Returns a valid section descriptor
 506  * or NULL on error.
 507  */
 508 static Elf_Scn *
 509 get_scnfd(Elf * e_file, int shstrtab, int SCN_TYPE)
 510 {
 511         Elf_Scn *fd_scn;
 512         GElf_Shdr shdr;
 513 
 514         if ((fd_scn = elf_getscn(e_file, shstrtab)) == NULL) {
 515                 return (NULL);
 516         }
 517 
 518         (void) gelf_getshdr(fd_scn, &shdr);
 519         if (shdr.sh_type != SCN_TYPE) {
 520                 return (NULL);
 521         }
 522         return (fd_scn);
 523 }
 524 
 525 
 526 /*
 527  * Print the symbol table.  This function does not print the contents
 528  * of the symbol table but sets up the parameters and then calls
 529  * print_symtab to print the symbols.  This function does not assume
 530  * that there is only one section of type SYMTAB.  Input is an opened
 531  * ELF file, a pointer to the ELF header, and the filename.
 532  */
 533 static void
 534 get_symtab(Elf *elf_file, char *filename)
 535 {
 536         Elf_Scn *scn, *scnfd;
 537         Elf_Data *data;
 538         GElf_Word symtabtype;
 539         size_t shstrndx;
 540 
 541         if (elf_getshdrstrndx(elf_file, &shstrndx) == -1) {
 542                 (void) fprintf(stderr, gettext(
 543                     "%s: %s: cannot get e_shstrndx\n"),
 544                     prog_name, filename);
 545                 return;
 546         }
 547 
 548         /* get section header string table */
 549         scnfd = get_scnfd(elf_file, shstrndx, SHT_STRTAB);
 550         if (scnfd == NULL) {
 551                 (void) fprintf(stderr, gettext(
 552                     "%s: %s: cannot get string table\n"),
 553                     prog_name, filename);
 554                 return;
 555         }
 556 
 557         data = elf_getdata(scnfd, NULL);
 558         if (data->d_size == 0) {
 559                 (void) fprintf(stderr, gettext(
 560                     "%s: %s: no data in string table\n"),
 561                     prog_name, filename);
 562                 return;
 563         }
 564 
 565         if (D_flag)
 566                 symtabtype = SHT_DYNSYM;
 567         else if (L_flag)
 568                 symtabtype = SHT_SUNW_LDYNSYM;
 569         else
 570                 symtabtype = SHT_SYMTAB;
 571 
 572         scn = 0;
 573         while ((scn = elf_nextscn(elf_file, scn)) != 0) {
 574                 GElf_Shdr shdr;
 575 
 576                 if (gelf_getshdr(scn, &shdr) == NULL) {
 577                         (void) fprintf(stderr, "%s: %s: %s:\n",
 578                             prog_name, filename, elf_errmsg(-1));
 579                         return;
 580                 }
 581 
 582                 if (shdr.sh_type == symtabtype) {
 583                         print_symtab(elf_file, shstrndx, scn,
 584                             &shdr, filename);
 585                 }
 586         } /* end while */
 587 }
 588 
 589 /*
 590  * Process member files of an archive.  This function provides
 591  * a loop through an archive equivalent the processing of
 592  * each_file for individual object files.
 593  */
 594 static void
 595 print_ar_files(int fd, Elf * elf_file, char *filename)
 596 {
 597         Elf_Arhdr  *p_ar;
 598         Elf     *arf;
 599         Elf_Cmd    cmd;
 600         Elf_Kind   file_type;
 601 
 602 
 603         cmd = ELF_C_READ;
 604         archive_name = filename;
 605         while ((arf = elf_begin(fd, cmd, elf_file)) != 0) {
 606                 p_ar = elf_getarhdr(arf);
 607                 if (p_ar == NULL) {
 608                         (void) fprintf(stderr, "%s: %s: %s\n",
 609                             prog_name, filename, elf_errmsg(-1));
 610                         return;
 611                 }
 612                 if (p_ar->ar_name[0] == '/') {
 613                         cmd = elf_next(arf);
 614                         (void) elf_end(arf);
 615                         continue;
 616                 }
 617 
 618                 if (!h_flag & !P_flag) {
 619                         if (p_flag)
 620                                 (void) printf("\n\n%s[%s]:\n",
 621                                     filename, p_ar->ar_name);
 622                         else {
 623                                 if (A_flag != 0)
 624                                         (void) printf("\n\n%s%s[%s]:\n",
 625                                             A_header, filename, p_ar->ar_name);
 626                                 else
 627                                         (void) printf("\n\n%s[%s]:\n",
 628                                             filename, p_ar->ar_name);
 629                         }
 630                 }
 631                 file_type = elf_kind(arf);
 632                 if (file_type == ELF_K_ELF) {
 633                         process(arf, p_ar->ar_name);
 634                 } else {
 635                         (void) fprintf(stderr, gettext(
 636                             "%s: %s: invalid file type\n"),
 637                             prog_name, p_ar->ar_name);
 638                         cmd = elf_next(arf);
 639                         (void) elf_end(arf);
 640                         errflag++;
 641                         continue;
 642                 }
 643 
 644                 cmd = elf_next(arf);
 645                 (void) elf_end(arf);
 646         } /* end while */
 647 }
 648 
 649 static void print_header(int);
 650 #ifndef XPG4
 651 static void print_with_uflag(SYM *, char *);
 652 #endif
 653 static void print_with_pflag(int, Elf *, unsigned int, SYM *, char *);
 654 static void print_with_Pflag(int, Elf *, unsigned int, SYM *);
 655 static void print_with_otherflags(int, Elf *, unsigned int,
 656                 SYM *, char *);
 657 /*
 658  * Print the symbol table according to the flags that were
 659  * set, if any.  Input is an opened ELF file, the section name,
 660  * the section header, the section descriptor, and the filename.
 661  * First get the symbol table with a call to elf_getdata.
 662  * Then translate the symbol table data in memory by calling
 663  * readsyms().  This avoids duplication of function calls
 664  * and improves sorting efficiency.  qsort is used when sorting
 665  * is requested.
 666  */
 667 static void
 668 print_symtab(Elf *elf_file, unsigned int shstrndx,
 669         Elf_Scn *p_sd, GElf_Shdr *shdr, char *filename)
 670 {
 671 
 672         Elf_Data * sd;
 673         SYM     *sym_data;
 674         SYM     *s;
 675         GElf_Sxword     count = 0;
 676         const int ndigits_arr[] = {
 677                 10,             /* FMT_T_DEC */
 678                 8,              /* FMT_T_HEX */
 679                 11,             /* FMT_T_OCT */
 680         };
 681         int ndigits;
 682 
 683         /*
 684          * Determine # of digits to use for each numeric value.
 685          */
 686         ndigits = ndigits_arr[fmt_flag];
 687         if (gelf_getclass(elf_file) == ELFCLASS64)
 688                 ndigits *= 2;
 689 
 690         /*
 691          * print header
 692          */
 693         print_header(ndigits);
 694 
 695         /*
 696          * get symbol table data
 697          */
 698         if (((sd = elf_getdata(p_sd, NULL)) == NULL) || (sd->d_size == 0)) {
 699                 (void) fprintf(stderr,
 700                     gettext("%s: %s: no symbol table data\n"),
 701                     prog_name, filename);
 702                 return;
 703         }
 704         count = shdr->sh_size / shdr->sh_entsize;
 705 
 706         /*
 707          * translate symbol table data
 708          */
 709         sym_data = readsyms(sd, count, elf_file, shdr->sh_link,
 710             (unsigned int)elf_ndxscn(p_sd));
 711         if (sym_data == NULL) {
 712                 (void) fprintf(stderr, gettext(
 713                     "%s: %s: problem reading symbol data\n"),
 714                     prog_name, filename);
 715                 return;
 716         }
 717         qsort((char *)sym_data, count-1, sizeof (SYM),
 718             (int (*)(const void *, const void *))compare);
 719         s = sym_data;
 720         while (count > 1) {
 721 #ifndef XPG4
 722                 if (u_flag) {
 723                         /*
 724                          * U_flag specified
 725                          */
 726                         print_with_uflag(sym_data, filename);
 727                 } else if (p_flag)
 728 #else
 729                 if (p_flag)
 730 #endif
 731                         print_with_pflag(ndigits, elf_file, shstrndx,
 732                             sym_data, filename);
 733                 else if (P_flag)
 734                         print_with_Pflag(ndigits, elf_file, shstrndx,
 735                             sym_data);
 736                 else
 737                         print_with_otherflags(ndigits, elf_file,
 738                             shstrndx, sym_data, filename);
 739                 sym_data++;
 740                 count--;
 741         }
 742 
 743         free(s);                /* allocated in readsym() */
 744 }
 745 
 746 /*
 747  * Return appropriate keyletter(s) for -p option.
 748  * Returns an index into the key[][] table or NULL if
 749  * the value of the keyletter is unknown.
 750  */
 751 static char *
 752 lookup(int a, int b)
 753 {
 754         return (((a < TYPE) && (b < BIND)) ? key[a][b] : NULL);
 755 }
 756 
 757 /*
 758  * Return TRUE(1) if the given section is ".bss" for "-p" option.
 759  * Return FALSE(0) if not ".bss" section.
 760  */
 761 static int
 762 is_bss_section(unsigned int shndx, Elf * elf_file, unsigned int shstrndx)
 763 {
 764         Elf_Scn *scn            = elf_getscn(elf_file, shndx);
 765         char    *sym_name;
 766 
 767         if (scn != NULL) {
 768                 GElf_Shdr shdr;
 769                 (void) gelf_getshdr(scn, &shdr);
 770                 sym_name = elf_strptr(elf_file, shstrndx, shdr.sh_name);
 771                 if (strcmp(BSS_SECN, sym_name) == 0)
 772                         return (1);
 773         }
 774         return (0);
 775 }
 776 
 777 /*
 778  * Translate symbol table data particularly for sorting.
 779  * Input is the symbol table data structure, number of symbols,
 780  * opened ELF file, and the string table link offset.
 781  */
 782 static SYM *
 783 readsyms(Elf_Data * data, GElf_Sxword num, Elf *elf,
 784         unsigned int link, unsigned int symscnndx)
 785 {
 786         SYM             *s, *buf;
 787         GElf_Sym        sym;
 788         Elf32_Word      *symshndx = 0;
 789         unsigned int    nosymshndx = 0;
 790         int             i;
 791 
 792         if ((buf = calloc(num, sizeof (SYM))) == NULL) {
 793                 (void) fprintf(stderr, gettext("%s: cannot allocate memory\n"),
 794                     prog_name);
 795                 return (NULL);
 796         }
 797 
 798         s = buf;        /* save pointer to head of array */
 799 
 800         for (i = 1; i < num; i++, buf++) {
 801                 (void) gelf_getsym(data, i, &sym);
 802 
 803                 buf->indx = i;
 804                 /* allow to work on machines where NULL-derefs dump core */
 805                 if (sym.st_name == 0)
 806                         buf->name = "";
 807                 else if (C_flag) {
 808                         const char *dn;
 809                         char *name = (char *)elf_strptr(elf, link, sym.st_name);
 810                         dn = conv_demangle_name(name);
 811                         if (strcmp(dn, name) == 0) {    /* Not demangled */
 812                                 if (exotic(name)) {
 813                                         name = FormatName(name, d_buf);
 814                                 }
 815                         } else {  /* name demangled */
 816                                 name = FormatName(name, dn);
 817                         }
 818                         buf->name = name;
 819                 }
 820                 else
 821                         buf->name = (char *)elf_strptr(elf, link, sym.st_name);
 822 
 823                 buf->value   = sym.st_value;
 824                 buf->size    = sym.st_size;
 825                 buf->type    = GELF_ST_TYPE(sym.st_info);
 826                 buf->bind    = GELF_ST_BIND(sym.st_info);
 827                 buf->other   = sym.st_other;
 828                 if ((sym.st_shndx == SHN_XINDEX) &&
 829                     (symshndx == 0) && (nosymshndx == 0)) {
 830                         Elf_Scn         *_scn;
 831                         GElf_Shdr       _shdr;
 832                         _scn = 0;
 833                         while ((_scn = elf_nextscn(elf, _scn)) != 0) {
 834                                 if (gelf_getshdr(_scn, &_shdr) == 0)
 835                                         break;
 836                                 if ((_shdr.sh_type == SHT_SYMTAB_SHNDX) &&
 837                                     (_shdr.sh_link == symscnndx)) {
 838                                         Elf_Data        *_data;
 839                                         if ((_data = elf_getdata(_scn,
 840                                             0)) != 0) {
 841                                                 symshndx =
 842                                                     (Elf32_Word *)_data->d_buf;
 843                                                 break;
 844                                         }
 845                                 }
 846                         }
 847                         nosymshndx = 1;
 848                 }
 849                 if ((symshndx) && (sym.st_shndx == SHN_XINDEX)) {
 850                         buf->shndx = symshndx[i];
 851                 } else {
 852                         buf->shndx   = sym.st_shndx;
 853                         if (sym.st_shndx >= SHN_LORESERVE)
 854                                 buf->flags |= FLG_SYM_SPECSEC;
 855                 }
 856         }       /* end for loop */
 857         return (s);
 858 }
 859 
 860 /*
 861  * compare either by name or by value for sorting.
 862  * This is the comparison function called by qsort to
 863  * sort the symbols either by name or value when requested.
 864  */
 865 static int
 866 compare(SYM *a, SYM *b)
 867 {
 868         if (v_flag) {
 869                 if (a->value > b->value)
 870                         return (1);
 871                 else
 872                         return ((a->value == b->value) -1);
 873         } else
 874                 return ((int)strcoll(a->name, b->name));
 875 }
 876 
 877 /*
 878  * Set up a header line for -A option.
 879  */
 880 static void
 881 set_A_header(char *fname)
 882 {
 883         if (A_flag == 0)
 884                 return;
 885 
 886         if (archive_name == (char *)0) {
 887                 (void) snprintf(A_header, sizeof (A_header), "%s: ", fname);
 888         } else {
 889                 (void) snprintf(A_header, sizeof (A_header), "%s[%s]: ",
 890                     archive_name, fname);
 891         }
 892 }
 893 
 894 /*
 895  * output functions
 896  *      The following functions are called from
 897  *      print_symtab().
 898  */
 899 
 900 /*
 901  * Print header line if needed.
 902  *
 903  * entry:
 904  *      ndigits - # of digits to be used to format an integer
 905  *              value, not counting any '0x' (hex) or '0' (octal) prefix.
 906  */
 907 static void
 908 print_header(int ndigits)
 909 {
 910         const char *fmt;
 911         const char *section_title;
 912         const int pad[] = {     /* Extra prefix characters for format */
 913                 1,              /* FMT_T_DEC: '|' */
 914                 3,              /* FMT_T_HEX: '|0x' */
 915                 2,              /* FMT_T_OCT: '|0' */
 916         };
 917         if (
 918 #ifndef XPG4
 919             !u_flag &&
 920 #endif
 921             !h_flag && !p_flag && !P_flag) {
 922                 (void) printf("\n");
 923                 if (!s_flag) {
 924                         fmt = "%-9s%-*s%-*s%-6s%-6s%-6s%-8s%s\n\n";
 925                         section_title = "Shndx";
 926                 } else {
 927                         fmt = "%-9s%-*s%-*s%-6s%-6s%-6s%-15s%s\n\n";
 928                         section_title = "Shname";
 929                 }
 930                 if (A_flag != 0)
 931                         (void) printf("%s", A_header);
 932                 ndigits += pad[fmt_flag];
 933                 (void) printf(fmt, "[Index]", ndigits, " Value",
 934                     ndigits, " Size", "Type", "Bind",
 935                     "Other", section_title, "Name");
 936         }
 937 }
 938 
 939 /*
 940  * If the symbol can be printed, then return 1.
 941  * If the symbol can not be printed, then return 0.
 942  */
 943 static int
 944 is_sym_print(SYM *sym_data)
 945 {
 946         /*
 947          * If -u flag is specified,
 948          *      the symbol has to be undefined.
 949          */
 950         if (u_flag != 0) {
 951                 if ((sym_data->shndx == SHN_UNDEF) &&
 952                     (strlen(sym_data->name) != 0))
 953                         return (1);
 954                 else
 955                         return (0);
 956         }
 957 
 958         /*
 959          * If -e flag is specified,
 960          *      the symbol has to be global or static.
 961          */
 962         if (e_flag != 0) {
 963                 switch (sym_data->type) {
 964                 case STT_NOTYPE:
 965                 case STT_OBJECT:
 966                 case STT_FUNC:
 967                 case STT_COMMON:
 968                 case STT_TLS:
 969                         switch (sym_data->bind) {
 970                         case STB_LOCAL:
 971                         case STB_GLOBAL:
 972                         case STB_WEAK:
 973                                 return (1);
 974                         default:
 975                                 return (0);
 976                         }
 977                 default:
 978                         return (0);
 979                 }
 980         }
 981 
 982         /*
 983          * If -g is specified,
 984          *      the symbol has to be global.
 985          */
 986         if (g_flag != 0) {
 987                 switch (sym_data->type) {
 988                 case STT_NOTYPE:
 989                 case STT_OBJECT:
 990                 case STT_FUNC:
 991                 case STT_COMMON:
 992                 case STT_TLS:
 993                         switch (sym_data->bind) {
 994                         case STB_GLOBAL:
 995                         case STB_WEAK:
 996                                 return (1);
 997                         default:
 998                                 return (0);
 999                         }
1000                 default:
1001                         return (0);
1002                 }
1003         }
1004 
1005         /*
1006          * If it comes here, any symbol can be printed.
1007          *      (So basically, -f is no-op.)
1008          */
1009         return (1);
1010 }
1011 
1012 #ifndef XPG4
1013 /*
1014  * -u flag specified
1015  */
1016 static void
1017 print_with_uflag(
1018         SYM *sym_data,
1019         char *filename
1020 )
1021 {
1022         if ((sym_data->shndx == SHN_UNDEF) && (strlen(sym_data->name))) {
1023                 if (!r_flag) {
1024                         if (R_flag) {
1025                                 if (archive_name != (char *)0)
1026                                         (void) printf("   %s:%s:%s\n",
1027                                             archive_name, filename,
1028                                             sym_data->name);
1029                                 else
1030                                         (void) printf("    %s:%s\n",
1031                                             filename, sym_data->name);
1032                         }
1033                         else
1034                                 (void) printf("    %s\n", sym_data->name);
1035                 }
1036                 else
1037                         (void) printf("    %s:%s\n", filename, sym_data->name);
1038         }
1039 }
1040 #endif
1041 
1042 /*
1043  * Print a symbol type representation suitable for the -p or -P formats.
1044  */
1045 static void
1046 print_brief_sym_type(Elf *elf_file, unsigned int shstrndx, SYM *sym_data)
1047 {
1048         const char      *sym_key = NULL;
1049 
1050         if ((sym_data->shndx == SHN_UNDEF) && (strlen(sym_data->name)))
1051                 sym_key = UNDEFINED;
1052         else if (sym_data->type == STT_SPARC_REGISTER) {
1053                 switch (sym_data->bind) {
1054                         case STB_LOCAL  : sym_key = REG_LOCL;
1055                                         break;
1056                         case STB_GLOBAL : sym_key = REG_GLOB;
1057                                         break;
1058                         case STB_WEAK   : sym_key = REG_WEAK;
1059                                         break;
1060                         default : sym_key = REG_GLOB;
1061                                         break;
1062                 }
1063         } else if (((sym_data->flags & FLG_SYM_SPECSEC) == 0) &&
1064             is_bss_section((int)sym_data->shndx, elf_file, shstrndx)) {
1065                 switch (sym_data->bind) {
1066                         case STB_LOCAL  : sym_key = BSS_LOCL;
1067                                         break;
1068                         case STB_GLOBAL : sym_key = BSS_GLOB;
1069                                         break;
1070                         case STB_WEAK   : sym_key = BSS_WEAK;
1071                                         break;
1072                         default : sym_key = BSS_GLOB;
1073                                         break;
1074                 }
1075 
1076         } else {
1077                 sym_key = lookup(sym_data->type, sym_data->bind);
1078         }
1079 
1080         if (sym_key != NULL) {
1081                 if (!l_flag)
1082                         (void) printf("%c ", sym_key[0]);
1083                 else
1084                         (void) printf("%-3s", sym_key);
1085         } else {
1086                 if (!l_flag)
1087                         (void) printf("%-2d", sym_data->type);
1088                 else
1089                         (void) printf("%-3d", sym_data->type);
1090         }
1091 }
1092 
1093 /*
1094  * -p flag specified
1095  */
1096 static void
1097 print_with_pflag(
1098         int ndigits,
1099         Elf *elf_file,
1100         unsigned int shstrndx,
1101         SYM *sym_data,
1102         char *filename
1103 )
1104 {
1105         const char * const fmt[] = {
1106                 "%.*llu ",      /* FMT_T_DEC */
1107                 "0x%.*llx ",    /* FMT_T_HEX */
1108                 "0%.*llo "      /* FMT_T_OCT */
1109         };
1110 
1111         if (is_sym_print(sym_data) != 1)
1112                 return;
1113         /*
1114          * -A header
1115          */
1116         if (A_flag != 0)
1117                 (void) printf("%s", A_header);
1118 
1119         /*
1120          * Symbol Value.
1121          *      (hex/octal/decimal)
1122          */
1123         (void) printf(fmt[fmt_flag], ndigits, EC_ADDR(sym_data->value));
1124 
1125 
1126         /*
1127          * Symbol Type.
1128          */
1129         print_brief_sym_type(elf_file, shstrndx, sym_data);
1130 
1131         if (!r_flag) {
1132                 if (R_flag) {
1133                         if (archive_name != (char *)0)
1134                                 (void) printf("%s:%s:%s\n", archive_name,
1135                                     filename, sym_data->name);
1136                         else
1137                                 (void) printf("%s:%s\n", filename,
1138                                     sym_data->name);
1139                 }
1140                 else
1141                         (void) printf("%s\n", sym_data->name);
1142         }
1143         else
1144                 (void) printf("%s:%s\n", filename, sym_data->name);
1145 }
1146 
1147 /*
1148  * -P flag specified
1149  */
1150 static void
1151 print_with_Pflag(
1152         int ndigits,
1153         Elf *elf_file,
1154         unsigned int shstrndx,
1155         SYM *sym_data
1156 )
1157 {
1158 #define SYM_LEN 10
1159         char sym_name[SYM_LEN+1];
1160         size_t len;
1161         const char * const fmt[] = {
1162                 "%*llu %*llu \n",       /* FMT_T_DEC */
1163                 "%*llx %*llx \n",       /* FMT_T_HEX */
1164                 "%*llo %*llo \n"        /* FMT_T_OCT */
1165         };
1166 
1167         if (is_sym_print(sym_data) != 1)
1168                 return;
1169         /*
1170          * -A header
1171          */
1172         if (A_flag != 0)
1173                 (void) printf("%s", A_header);
1174 
1175         /*
1176          * Symbol name
1177          */
1178         len = strlen(sym_data->name);
1179         if (len >= SYM_LEN)
1180                 (void) printf("%s ", sym_data->name);
1181         else {
1182                 (void) sprintf(sym_name, "%-10s", sym_data->name);
1183                 (void) printf("%s ", sym_name);
1184         }
1185 
1186         /*
1187          * Symbol Type.
1188          */
1189         print_brief_sym_type(elf_file, shstrndx, sym_data);
1190 
1191         /*
1192          * Symbol Value & size
1193          *      (hex/octal/decimal)
1194          */
1195         (void) printf(fmt[fmt_flag], ndigits, EC_ADDR(sym_data->value),
1196             ndigits, EC_XWORD(sym_data->size));
1197 }
1198 
1199 /*
1200  * other flags specified
1201  */
1202 static void
1203 print_with_otherflags(
1204         int ndigits,
1205         Elf *elf_file,
1206         unsigned int shstrndx,
1207         SYM *sym_data,
1208         char *filename
1209 )
1210 {
1211         const char * const fmt_value_size[] = {
1212                 "%*llu|%*lld|",         /* FMT_T_DEC */
1213                 "0x%.*llx|0x%.*llx|",   /* FMT_T_HEX */
1214                 "0%.*llo|0%.*llo|"      /* FMT_T_OCT */
1215         };
1216         const char * const fmt_int[] = {
1217                 "%-5d",                 /* FMT_T_DEC */
1218                 "%#-5x",                /* FMT_T_HEX */
1219                 "%#-5o"                 /* FMT_T_OCT */
1220         };
1221 
1222         if (is_sym_print(sym_data) != 1)
1223                 return;
1224         (void) printf("%s", A_header);
1225         (void) printf("[%d]\t|", sym_data->indx);
1226         (void) printf(fmt_value_size[fmt_flag], ndigits,
1227             EC_ADDR(sym_data->value), ndigits, EC_XWORD(sym_data->size));
1228 
1229         switch (sym_data->type) {
1230         case STT_NOTYPE:(void) printf("%-5s", "NOTY"); break;
1231         case STT_OBJECT:(void) printf("%-5s", "OBJT"); break;
1232         case STT_FUNC:  (void) printf("%-5s", "FUNC"); break;
1233         case STT_SECTION:(void) printf("%-5s", "SECT"); break;
1234         case STT_FILE:  (void) printf("%-5s", "FILE"); break;
1235         case STT_COMMON: (void) printf("%-5s", "COMM"); break;
1236         case STT_TLS:   (void) printf("%-5s", "TLS "); break;
1237         case STT_SPARC_REGISTER: (void) printf("%-5s", "REGI"); break;
1238         default:
1239                 (void) printf(fmt_int[fmt_flag], sym_data->type);
1240         }
1241         (void) printf("|");
1242         switch (sym_data->bind) {
1243         case STB_LOCAL: (void) printf("%-5s", "LOCL"); break;
1244         case STB_GLOBAL:(void) printf("%-5s", "GLOB"); break;
1245         case STB_WEAK:  (void) printf("%-5s", "WEAK"); break;
1246         default:
1247                 (void) printf("%-5d", sym_data->bind);
1248                 (void) printf(fmt_int[fmt_flag], sym_data->bind);
1249         }
1250         (void) printf("|");
1251         (void) printf(fmt_int[fmt_flag], sym_data->other);
1252         (void)  printf("|");
1253 
1254         if (sym_data->shndx == SHN_UNDEF) {
1255                 if (!s_flag)
1256                         (void) printf("%-7s", "UNDEF");
1257                 else
1258                         (void) printf("%-14s", "UNDEF");
1259         } else if (sym_data->shndx == SHN_SUNW_IGNORE) {
1260                 if (!s_flag)
1261                         (void) printf("%-7s", "IGNORE");
1262                 else
1263                         (void) printf("%-14s", "IGNORE");
1264         } else if ((sym_data->flags & FLG_SYM_SPECSEC) &&
1265             (sym_data->shndx == SHN_ABS)) {
1266                 if (!s_flag)
1267                         (void) printf("%-7s", "ABS");
1268                 else
1269                         (void) printf("%-14s", "ABS");
1270         } else if ((sym_data->flags & FLG_SYM_SPECSEC) &&
1271             (sym_data->shndx == SHN_COMMON)) {
1272                 if (!s_flag)
1273                         (void) printf("%-7s", "COMMON");
1274                 else
1275                         (void) printf("%-14s", "COMMON");
1276         } else {
1277                 if (s_flag) {
1278                         Elf_Scn *scn = elf_getscn(elf_file, sym_data->shndx);
1279                         GElf_Shdr shdr;
1280 
1281                         if ((gelf_getshdr(scn, &shdr) != 0) &&
1282                             (shdr.sh_name != 0)) {
1283                                 (void) printf("%-14s",
1284                                     (char *)elf_strptr(elf_file,
1285                                     shstrndx, shdr.sh_name));
1286                         } else {
1287                                 (void) printf("%-14d", sym_data->shndx);
1288                         }
1289                 } else {
1290                         (void) printf("%-7d", sym_data->shndx);
1291                 }
1292         }
1293         (void) printf("|");
1294         if (!r_flag) {
1295                 if (R_flag) {
1296                         if (archive_name != (char *)0)
1297                                 (void) printf("%s:%s:%s\n", archive_name,
1298                                     filename, sym_data->name);
1299                         else
1300                                 (void) printf("%s:%s\n", filename,
1301                                     sym_data->name);
1302                 }
1303                 else
1304                         (void) printf("%s\n", sym_data->name);
1305         }
1306         else
1307                 (void) printf("%s:%s\n", filename, sym_data->name);
1308 }
1309 
1310 /*
1311  * C++ name demangling supporting routines
1312  */
1313 static const char *ctor_str = "static constructor function for %s";
1314 static const char *dtor_str = "static destructor function for %s";
1315 static const char *ptbl_str = "pointer to the virtual table vector for %s";
1316 static const char *vtbl_str = "virtual table for %s";
1317 
1318 /*
1319  * alloc memory and create name in necessary format.
1320  * Return name string
1321  */
1322 static char *
1323 FormatName(char *OldName, const char *NewName)
1324 {
1325         char *s = p_flag ?
1326             "%s\n             [%s]" :
1327             "%s\n\t\t\t\t\t\t       [%s]";
1328         size_t length = strlen(s)+strlen(NewName)+strlen(OldName)-3;
1329         char *hold = OldName;
1330         OldName = malloc(length);
1331         /*LINTED*/
1332         (void) snprintf(OldName, length, s, NewName, hold);
1333         return (OldName);
1334 }
1335 
1336 
1337 /*
1338  * Return 1 when s is an exotic name, 0 otherwise.  s remains unchanged,
1339  * the exotic name, if exists, is saved in d_buf.
1340  */
1341 static int
1342 exotic(const char *in_str)
1343 {
1344         static char     *buff = 0;
1345         static size_t   buf_size;
1346 
1347         size_t          sym_len = strlen(in_str) + 1;
1348         int             tag = 0;
1349         char            *s;
1350 
1351         /*
1352          * We will need to modify the symbol (in_str) as we are analyzing it,
1353          * so copy it into a buffer so that we can play around with it.
1354          */
1355         if (buff == NULL) {
1356                 buff = malloc(DEF_MAX_SYM_SIZE);
1357                 buf_size = DEF_MAX_SYM_SIZE;
1358         }
1359 
1360         if (sym_len > buf_size) {
1361                 if (buff)
1362                         free(buff);
1363                 buff = malloc(sym_len);
1364                 buf_size = sym_len;
1365         }
1366 
1367         if (buff == NULL) {
1368                 (void) fprintf(stderr, gettext(
1369                     "%s: cannot allocate memory\n"), prog_name);
1370                 exit(NOALLOC);
1371         }
1372         s = strcpy(buff, in_str);
1373 
1374 
1375         if (strncmp(s, "__sti__", 7) == 0) {
1376                 s += 7; tag = 1;
1377                 parse_fn_and_print(ctor_str, s);
1378         } else if (strncmp(s, "__std__", 7) == 0) {
1379                 s += 7; tag = 1;
1380                 parse_fn_and_print(dtor_str, s);
1381         } else if (strncmp(s, "__vtbl__", 8) == 0) {
1382                 s += 8; tag = 1;
1383                 parsename(s);
1384                 (void) sprintf(d_buf, vtbl_str, p_buf);
1385         } else if (strncmp(s, "__ptbl_vec__", 12) == 0) {
1386                 s += 12; tag = 1;
1387                 parse_fn_and_print(ptbl_str, s);
1388         }
1389         return (tag);
1390 }
1391 
1392 void
1393 parsename(char *s)
1394 {
1395         register int len;
1396         char c, *orig = s;
1397         *p_buf = '\0';
1398         (void) strcat(p_buf, "class ");
1399         while (isdigit(*s)) s++;
1400         c = *s;
1401         *s = '\0';
1402         len = atoi(orig);
1403         *s = c;
1404         if (*(s+len) == '\0') { /* only one class name */
1405                 (void) strcat(p_buf, s);
1406                 return;
1407         } else
1408         { /* two classname  %drootname__%dchildname */
1409                 char *root, *child, *child_len_p;
1410                 int child_len;
1411                 root = s;
1412                 child = s + len + 2;
1413                 child_len_p = child;
1414                 if (!isdigit(*child)) {
1415                         /* ptbl file name */
1416                         /*  %drootname__%filename */
1417                         /* kludge for getting rid of '_' in file name */
1418                         char *p;
1419                         c = *(root + len);
1420                         *(root + len) = '\0';
1421                         (void) strcat(p_buf, root);
1422                         *(root + len) = c;
1423                         (void) strcat(p_buf, " in ");
1424                         for (p = child; *p != '_'; ++p)
1425                                 ;
1426                         c = *p;
1427                         *p = '.';
1428                         (void) strcat(p_buf, child);
1429                         *p = c;
1430                         return;
1431                 }
1432 
1433                 while (isdigit(*child))
1434                         child++;
1435                 c = *child;
1436                 *child = '\0';
1437                 child_len = atoi(child_len_p);
1438                 *child = c;
1439                 if (*(child + child_len) == '\0') {
1440                         (void) strcat(p_buf, child);
1441                         (void) strcat(p_buf, " derived from ");
1442                         c = *(root + len);
1443                         *(root + len) = '\0';
1444                         (void) strcat(p_buf, root);
1445                         *(root + len) = c;
1446                         return;
1447                 } else {
1448                         /* %drootname__%dchildname__filename */
1449                         /* kludge for getting rid of '_' in file name */
1450                         char *p;
1451                         c = *(child + child_len);
1452                         *(child + child_len) = '\0';
1453                         (void) strcat(p_buf, child);
1454                         *(child+child_len) = c;
1455                         (void) strcat(p_buf, " derived from ");
1456                         c = *(root + len);
1457                         *(root + len) = '\0';
1458                         (void) strcat(p_buf, root);
1459                         *(root + len) = c;
1460                         (void) strcat(p_buf, " in ");
1461                         for (p = child + child_len + 2; *p != '_'; ++p)
1462                                 ;
1463                         c = *p;
1464                         *p = '.';
1465                         (void) strcat(p_buf, child + child_len + 2);
1466                         *p = c;
1467                         return;
1468                 }
1469         }
1470 }
1471 
1472 void
1473 parse_fn_and_print(const char *str, char *s)
1474 {
1475         char            c, *p1, *p2;
1476         int             yes = 1;
1477 
1478         if ((p1 = p2 =  strstr(s, "_c_")) == NULL)
1479                 if ((p1 = p2 =  strstr(s, "_C_")) == NULL)
1480                         if ((p1 = p2 =  strstr(s, "_cc_")) == NULL)
1481                                 if ((p1 = p2 =  strstr(s, "_cxx_")) == NULL)
1482                                         if ((p1 = p2 = strstr(s, "_h_")) ==
1483                                             NULL)
1484                         yes = 0;
1485                         else
1486                                                 p2 += 2;
1487                                 else
1488                                         p2 += 4;
1489                         else
1490                                 p2 += 3;
1491                 else
1492                         p2 += 2;
1493         else
1494                 p2 += 2;
1495 
1496         if (yes) {
1497         *p1 = '.';
1498                 c = *p2;
1499                 *p2 = '\0';
1500         }
1501 
1502         for (s = p1;  *s != '_';  --s)
1503                 ;
1504         ++s;
1505 
1506         (void) sprintf(d_buf, str, s);
1507 
1508         if (yes) {
1509                 *p1 = '_';
1510                 *p2 = c;
1511         }
1512 }