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