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