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