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