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