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