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