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 (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
28 */
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <unistd.h>
33 #include <ctype.h>
34 #include <locale.h>
35 #include <libelf.h>
36 #include <sys/elf_SPARC.h>
37
38
39 /* exit return codes */
40 #define NOARGS 1
41 #define BADELF 2
42 #define NOALLOC 3
43
44 #include <fcntl.h>
45 #include <sys/stat.h>
46 #include <errno.h>
47 #include <string.h>
48 #include <dlfcn.h>
49
50 #include "sgs.h"
51 #include "conv.h"
52 #include "gelf.h"
53
54 typedef struct { /* structure to translate symbol table data */
55 int indx;
56 char *name;
57 GElf_Addr value;
58 GElf_Xword size;
59 int type;
60 int bind;
61 unsigned char other;
62 unsigned int shndx;
63 unsigned int flags; /* flags relevant to entry */
64 } SYM;
65
66 #define FLG_SYM_SPECSEC 0x00000001 /* reserved scn index */
67 /* (SHN_ABS, SHN_COMMON, ...) */
68
69 #define UNDEFINED "U"
70 #define BSS_GLOB "B"
71 #define BSS_WEAK "B*"
72 #define BSS_LOCL "b"
73 #define BSS_SECN ".bss"
74 #define REG_GLOB "R"
75 #define REG_WEAK "R*"
76 #define REG_LOCL "r"
77
78 #define OPTSTR ":APDoxhvnursplLCVefgRTt:" /* option string for getopt() */
79
80 #define DATESIZE 60
81
82 #define TYPE 7
83 #define BIND 3
84
85 #define DEF_MAX_SYM_SIZE 256
86
87 static char *key[TYPE][BIND];
88
89 /*
90 * Format type used for printing value and size items.
91 * The non-negative values here are used as array indices into
92 * several arrays found below. Renumbering, or adding items,
93 * will require changes to those arrays as well.
94 */
95 typedef enum {
96 FMT_T_NONE = -1, /* No format type yet assigned */
97
98 /* The following are used as array indices */
99 FMT_T_DEC = 0,
100 FMT_T_HEX = 1,
101 FMT_T_OCT = 2
102 } FMT_T;
103
104 /*
105 * Determine whether a proposed format type is compatible with the current
106 * setting. We allow setting the format as long as it hasn't already
107 * been done, or if the new setting is the same as the current one.
108 */
109 #define COMPAT_FMT_FLAG(new_fmt_flag) \
110 (fmt_flag == FMT_T_NONE) || (fmt_flag == new_fmt_flag)
111
112 static FMT_T fmt_flag = FMT_T_NONE; /* format style to use for value/size */
113
114 static int /* flags: ?_flag corresponds to ? option */
115 h_flag = 0, /* suppress printing of headings */
116 v_flag = 0, /* sort external symbols by value */
117 n_flag = 0, /* sort external symbols by name */
118 u_flag = 0, /* print only undefined symbols */
119 r_flag = 0, /* prepend object file or archive name */
120 /* to each symbol name */
121 R_flag = 0, /* if "-R" issued then prepend archive name, */
122 /* object file name to each symbol */
123 s_flag = 0, /* print section name instead of section index */
124 p_flag = 0, /* produce terse output */
125 P_flag = 0, /* Portable format output */
126 l_flag = 0, /* produce long listing of output */
127 L_flag = 0, /* print SUNW_LDYNSYM instead of SYMTAB */
128 D_flag = 0, /* print DYNSYM instead of SYMTAB */
129 C_flag = 0, /* print decoded C++ names */
130 A_flag = 0, /* File name */
131 e_flag = 0, /* -e flag */
132 g_flag = 0, /* -g flag */
133 V_flag = 0; /* print version information */
134 static char A_header[DEF_MAX_SYM_SIZE+1] = {0};
135
136 static char *prog_name;
137 static char *archive_name = (char *)0;
138 static int errflag = 0;
139 static void usage();
140 static void each_file(char *);
141 static void process(Elf *, char *);
142 static Elf_Scn * get_scnfd(Elf *, int, int);
143 static void get_symtab(Elf *, char *);
144 static SYM * readsyms(Elf_Data *, GElf_Sxword, Elf *, unsigned int,
145 unsigned int);
146 static int compare(SYM *, SYM *);
147 static char *lookup(int, int);
148 static int is_bss_section(unsigned int, Elf *, unsigned int);
149 static void print_ar_files(int, Elf *, char *);
150 static void print_symtab(Elf *, unsigned int, Elf_Scn *, GElf_Shdr *, char *);
151 static void parsename(char *);
152 static void parse_fn_and_print(const char *, char *);
153 static char d_buf[512];
154 static char p_buf[512];
155 static int exotic(const char *s);
156 static void set_A_header(char *);
157 static char *FormatName(char *, const char *);
158
159
160
161 /*
162 * Parses the command line options and then
163 * calls each_file() to process each file.
164 */
165 int
main(int argc,char * argv[],char * envp[])166 main(int argc, char *argv[], char *envp[])
167 {
168 char *optstr = OPTSTR; /* option string used by getopt() */
169 int optchar;
170 FMT_T new_fmt_flag;
171
172 #ifndef XPG4
173 /*
174 * Check for a binary that better fits this architecture.
175 */
176 (void) conv_check_native(argv, envp);
177 #endif
178
179 /* table of keyletters for use with -p and -P options */
180 key[STT_NOTYPE][STB_LOCAL] = "n";
181 key[STT_NOTYPE][STB_GLOBAL] = "N";
182 key[STT_NOTYPE][STB_WEAK] = "N*";
183 key[STT_OBJECT][STB_LOCAL] = "d";
184 key[STT_OBJECT][STB_GLOBAL] = "D";
185 key[STT_OBJECT][STB_WEAK] = "D*";
186 key[STT_FUNC][STB_LOCAL] = "t";
187 key[STT_FUNC][STB_GLOBAL] = "T";
188 key[STT_FUNC][STB_WEAK] = "T*";
189 key[STT_SECTION][STB_LOCAL] = "s";
190 key[STT_SECTION][STB_GLOBAL] = "S";
191 key[STT_SECTION][STB_WEAK] = "S*";
192 key[STT_FILE][STB_LOCAL] = "f";
193 key[STT_FILE][STB_GLOBAL] = "F";
194 key[STT_FILE][STB_WEAK] = "F*";
195 key[STT_COMMON][STB_LOCAL] = "c";
196 key[STT_COMMON][STB_GLOBAL] = "C";
197 key[STT_COMMON][STB_WEAK] = "C*";
198 key[STT_TLS][STB_LOCAL] = "l";
199 key[STT_TLS][STB_GLOBAL] = "L";
200 key[STT_TLS][STB_WEAK] = "L*";
201
202 prog_name = argv[0];
203
204 (void) setlocale(LC_ALL, "");
205 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
206 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
207 #endif
208 (void) textdomain(TEXT_DOMAIN);
209
210 while ((optchar = getopt(argc, argv, optstr)) != -1) {
211 switch (optchar) {
212 case 'o': if (COMPAT_FMT_FLAG(FMT_T_OCT))
213 fmt_flag = FMT_T_OCT;
214 else
215 (void) fprintf(stderr, gettext(
216 "%s: -x or -t set, -o ignored\n"),
217 prog_name);
218 break;
219 case 'x': if (COMPAT_FMT_FLAG(FMT_T_HEX))
220 fmt_flag = FMT_T_HEX;
221 else
222 (void) fprintf(stderr, gettext(
223 "%s: -o or -t set, -x ignored\n"),
224 prog_name);
225 break;
226 case 'h': h_flag = 1;
227 break;
228 case 'v': if (!n_flag)
229 v_flag = 1;
230 else
231 (void) fprintf(stderr, gettext(
232 "%s: -n set, -v ignored\n"),
233 prog_name);
234 break;
235 case 'n': if (!v_flag)
236 n_flag = 1;
237 else
238 (void) fprintf(stderr, gettext(
239 "%s: -v set, -n ignored\n"),
240 prog_name);
241 break;
242 case 'u': if (!e_flag && !g_flag)
243 u_flag = 1;
244 else
245 (void) fprintf(stderr, gettext(
246 "%s: -e or -g set, -u ignored\n"),
247 prog_name);
248 break;
249 case 'e': if (!u_flag && !g_flag)
250 e_flag = 1;
251 else
252 (void) fprintf(stderr, gettext(
253 "%s: -u or -g set, -e ignored\n"),
254 prog_name);
255 break;
256 case 'g': if (!u_flag && !e_flag)
257 g_flag = 1;
258 else
259 (void) fprintf(stderr, gettext(
260 "%s: -u or -e set, -g ignored\n"),
261 prog_name);
262 break;
263 case 'r': if (R_flag) {
264 R_flag = 0;
265 (void) fprintf(stderr, gettext(
266 "%s: -r set, -R ignored\n"),
267 prog_name);
268 }
269 r_flag = 1;
270 break;
271 case 's': s_flag = 1;
272 break;
273 case 'p': if (P_flag == 1) {
274 (void) fprintf(stderr, gettext(
275 "nm: -P set. -p ignored\n"));
276 } else
277 p_flag = 1;
278 break;
279 case 'P': if (p_flag == 1) {
280 (void) fprintf(stderr, gettext(
281 "nm: -p set. -P ignored\n"));
282 } else
283 P_flag = 1;
284 break;
285 case 'l': l_flag = 1;
286 break;
287 case 'L': if (D_flag == 1) {
288 (void) fprintf(stderr, gettext(
289 "nm: -D set. -L ignored\n"));
290 } else
291 L_flag = 1;
292 break;
293 case 'D': if (L_flag == 1) {
294 (void) fprintf(stderr, gettext(
295 "nm: -L set. -D ignored\n"));
296 } else
297 D_flag = 1;
298 break;
299 case 'C':
300 C_flag = 1;
301 break;
302 case 'A': A_flag = 1;
303 break;
304 case 'V': V_flag = 1;
305 (void) fprintf(stderr, "nm: %s %s\n",
306 (const char *)SGU_PKG,
307 (const char *)SGU_REL);
308 break;
309 case 'f': /* -f is a noop, see man page */
310 break;
311 case 'R': if (!r_flag)
312 R_flag = 1;
313 else
314 (void) fprintf(stderr, gettext(
315 "%s: -r set, -R ignored\n"),
316 prog_name);
317 break;
318 case 'T':
319 break;
320 case 't': if (strcmp(optarg, "o") == 0) {
321 new_fmt_flag = FMT_T_OCT;
322 } else if (strcmp(optarg, "d") == 0) {
323 new_fmt_flag = FMT_T_DEC;
324 } else if (strcmp(optarg, "x") == 0) {
325 new_fmt_flag = FMT_T_HEX;
326 } else {
327 new_fmt_flag = FMT_T_NONE;
328 }
329 if (new_fmt_flag == FMT_T_NONE) {
330 errflag += 1;
331 (void) fprintf(stderr, gettext(
332 "nm: -t requires radix value (d, o, x): %s\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
usage()380 usage()
381 {
382 (void) fprintf(stderr, gettext(
383 "Usage: nm [-ACDhLlnPpRrsTVv] [-efox] [-g | -u] [-t d|o|x] 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
each_file(char * filename)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
process(Elf * elf_file,char * filename)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 *
get_scnfd(Elf * e_file,int shstrtab,int SCN_TYPE)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
get_symtab(Elf * elf_file,char * filename)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_getshdrstrndx(elf_file, &shstrndx) == -1) {
542 (void) fprintf(stderr, gettext(
543 "%s: %s: cannot 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: cannot 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
print_ar_files(int fd,Elf * elf_file,char * filename)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 (p_ar->ar_name[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
print_symtab(Elf * elf_file,unsigned int shstrndx,Elf_Scn * p_sd,GElf_Shdr * shdr,char * filename)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) fprintf(stderr,
700 gettext("%s: %s: no symbol table data\n"),
701 prog_name, filename);
702 return;
703 }
704 count = shdr->sh_size / shdr->sh_entsize;
705
706 /*
707 * translate symbol table data
708 */
709 sym_data = readsyms(sd, count, elf_file, shdr->sh_link,
710 (unsigned int)elf_ndxscn(p_sd));
711 if (sym_data == NULL) {
712 (void) fprintf(stderr, gettext(
713 "%s: %s: problem reading symbol data\n"),
714 prog_name, filename);
715 return;
716 }
717 qsort((char *)sym_data, count-1, sizeof (SYM),
718 (int (*)(const void *, const void *))compare);
719 s = sym_data;
720 while (count > 1) {
721 #ifndef XPG4
722 if (u_flag) {
723 /*
724 * U_flag specified
725 */
726 print_with_uflag(sym_data, filename);
727 } else if (p_flag)
728 #else
729 if (p_flag)
730 #endif
731 print_with_pflag(ndigits, elf_file, shstrndx,
732 sym_data, filename);
733 else if (P_flag)
734 print_with_Pflag(ndigits, elf_file, shstrndx,
735 sym_data);
736 else
737 print_with_otherflags(ndigits, elf_file,
738 shstrndx, sym_data, filename);
739 sym_data++;
740 count--;
741 }
742
743 free(s); /* allocated in readsym() */
744 }
745
746 /*
747 * Return appropriate keyletter(s) for -p option.
748 * Returns an index into the key[][] table or NULL if
749 * the value of the keyletter is unknown.
750 */
751 static char *
lookup(int a,int b)752 lookup(int a, int b)
753 {
754 return (((a < TYPE) && (b < BIND)) ? key[a][b] : NULL);
755 }
756
757 /*
758 * Return TRUE(1) if the given section is ".bss" for "-p" option.
759 * Return FALSE(0) if not ".bss" section.
760 */
761 static int
is_bss_section(unsigned int shndx,Elf * elf_file,unsigned int shstrndx)762 is_bss_section(unsigned int shndx, Elf * elf_file, unsigned int shstrndx)
763 {
764 Elf_Scn *scn = elf_getscn(elf_file, shndx);
765 char *sym_name;
766
767 if (scn != NULL) {
768 GElf_Shdr shdr;
769 (void) gelf_getshdr(scn, &shdr);
770 sym_name = elf_strptr(elf_file, shstrndx, shdr.sh_name);
771 if (strcmp(BSS_SECN, sym_name) == 0)
772 return (1);
773 }
774 return (0);
775 }
776
777 /*
778 * Translate symbol table data particularly for sorting.
779 * Input is the symbol table data structure, number of symbols,
780 * opened ELF file, and the string table link offset.
781 */
782 static SYM *
readsyms(Elf_Data * data,GElf_Sxword num,Elf * elf,unsigned int link,unsigned int symscnndx)783 readsyms(Elf_Data * data, GElf_Sxword num, Elf *elf,
784 unsigned int link, unsigned int symscnndx)
785 {
786 SYM *s, *buf;
787 GElf_Sym sym;
788 Elf32_Word *symshndx = 0;
789 unsigned int nosymshndx = 0;
790 int i;
791
792 if ((buf = calloc(num, sizeof (SYM))) == NULL) {
793 (void) fprintf(stderr, gettext("%s: cannot allocate memory\n"),
794 prog_name);
795 return (NULL);
796 }
797
798 s = buf; /* save pointer to head of array */
799
800 for (i = 1; i < num; i++, buf++) {
801 (void) gelf_getsym(data, i, &sym);
802
803 buf->indx = i;
804 /* allow to work on machines where NULL-derefs dump core */
805 if (sym.st_name == 0)
806 buf->name = "";
807 else if (C_flag) {
808 const char *dn;
809 char *name = (char *)elf_strptr(elf, link, sym.st_name);
810 dn = conv_demangle_name(name);
811 if (strcmp(dn, name) == 0) { /* Not demangled */
812 if (exotic(name)) {
813 name = FormatName(name, d_buf);
814 }
815 } else { /* name demangled */
816 name = FormatName(name, dn);
817 }
818 buf->name = name;
819 }
820 else
821 buf->name = (char *)elf_strptr(elf, link, sym.st_name);
822
823 buf->value = sym.st_value;
824 buf->size = sym.st_size;
825 buf->type = GELF_ST_TYPE(sym.st_info);
826 buf->bind = GELF_ST_BIND(sym.st_info);
827 buf->other = sym.st_other;
828 if ((sym.st_shndx == SHN_XINDEX) &&
829 (symshndx == 0) && (nosymshndx == 0)) {
830 Elf_Scn *_scn;
831 GElf_Shdr _shdr;
832 _scn = 0;
833 while ((_scn = elf_nextscn(elf, _scn)) != 0) {
834 if (gelf_getshdr(_scn, &_shdr) == 0)
835 break;
836 if ((_shdr.sh_type == SHT_SYMTAB_SHNDX) &&
837 (_shdr.sh_link == symscnndx)) {
838 Elf_Data *_data;
839 if ((_data = elf_getdata(_scn,
840 0)) != 0) {
841 symshndx =
842 (Elf32_Word *)_data->d_buf;
843 break;
844 }
845 }
846 }
847 nosymshndx = 1;
848 }
849 if ((symshndx) && (sym.st_shndx == SHN_XINDEX)) {
850 buf->shndx = symshndx[i];
851 } else {
852 buf->shndx = sym.st_shndx;
853 if (sym.st_shndx >= SHN_LORESERVE)
854 buf->flags |= FLG_SYM_SPECSEC;
855 }
856 } /* end for loop */
857 return (s);
858 }
859
860 /*
861 * compare either by name or by value for sorting.
862 * This is the comparison function called by qsort to
863 * sort the symbols either by name or value when requested.
864 */
865 static int
compare(SYM * a,SYM * b)866 compare(SYM *a, SYM *b)
867 {
868 if (v_flag) {
869 if (a->value > b->value)
870 return (1);
871 else
872 return ((a->value == b->value) -1);
873 } else
874 return ((int)strcoll(a->name, b->name));
875 }
876
877 /*
878 * Set up a header line for -A option.
879 */
880 static void
set_A_header(char * fname)881 set_A_header(char *fname)
882 {
883 if (A_flag == 0)
884 return;
885
886 if (archive_name == (char *)0) {
887 (void) snprintf(A_header, sizeof (A_header), "%s: ", fname);
888 } else {
889 (void) snprintf(A_header, sizeof (A_header), "%s[%s]: ",
890 archive_name, fname);
891 }
892 }
893
894 /*
895 * output functions
896 * The following functions are called from
897 * print_symtab().
898 */
899
900 /*
901 * Print header line if needed.
902 *
903 * entry:
904 * ndigits - # of digits to be used to format an integer
905 * value, not counting any '0x' (hex) or '0' (octal) prefix.
906 */
907 static void
print_header(int ndigits)908 print_header(int ndigits)
909 {
910 const char *fmt;
911 const char *section_title;
912 const int pad[] = { /* Extra prefix characters for format */
913 1, /* FMT_T_DEC: '|' */
914 3, /* FMT_T_HEX: '|0x' */
915 2, /* FMT_T_OCT: '|0' */
916 };
917 if (
918 #ifndef XPG4
919 !u_flag &&
920 #endif
921 !h_flag && !p_flag && !P_flag) {
922 (void) printf("\n");
923 if (!s_flag) {
924 fmt = "%-9s%-*s%-*s%-6s%-6s%-6s%-8s%s\n\n";
925 section_title = "Shndx";
926 } else {
927 fmt = "%-9s%-*s%-*s%-6s%-6s%-6s%-15s%s\n\n";
928 section_title = "Shname";
929 }
930 if (A_flag != 0)
931 (void) printf("%s", A_header);
932 ndigits += pad[fmt_flag];
933 (void) printf(fmt, "[Index]", ndigits, " Value",
934 ndigits, " Size", "Type", "Bind",
935 "Other", section_title, "Name");
936 }
937 }
938
939 /*
940 * If the symbol can be printed, then return 1.
941 * If the symbol can not be printed, then return 0.
942 */
943 static int
is_sym_print(SYM * sym_data)944 is_sym_print(SYM *sym_data)
945 {
946 /*
947 * If -u flag is specified,
948 * the symbol has to be undefined.
949 */
950 if (u_flag != 0) {
951 if ((sym_data->shndx == SHN_UNDEF) &&
952 (strlen(sym_data->name) != 0))
953 return (1);
954 else
955 return (0);
956 }
957
958 /*
959 * If -e flag is specified,
960 * the symbol has to be global or static.
961 */
962 if (e_flag != 0) {
963 switch (sym_data->type) {
964 case STT_NOTYPE:
965 case STT_OBJECT:
966 case STT_FUNC:
967 case STT_COMMON:
968 case STT_TLS:
969 switch (sym_data->bind) {
970 case STB_LOCAL:
971 case STB_GLOBAL:
972 case STB_WEAK:
973 return (1);
974 default:
975 return (0);
976 }
977 default:
978 return (0);
979 }
980 }
981
982 /*
983 * If -g is specified,
984 * the symbol has to be global.
985 */
986 if (g_flag != 0) {
987 switch (sym_data->type) {
988 case STT_NOTYPE:
989 case STT_OBJECT:
990 case STT_FUNC:
991 case STT_COMMON:
992 case STT_TLS:
993 switch (sym_data->bind) {
994 case STB_GLOBAL:
995 case STB_WEAK:
996 return (1);
997 default:
998 return (0);
999 }
1000 default:
1001 return (0);
1002 }
1003 }
1004
1005 /*
1006 * If it comes here, any symbol can be printed.
1007 * (So basically, -f is no-op.)
1008 */
1009 return (1);
1010 }
1011
1012 #ifndef XPG4
1013 /*
1014 * -u flag specified
1015 */
1016 static void
print_with_uflag(SYM * sym_data,char * filename)1017 print_with_uflag(
1018 SYM *sym_data,
1019 char *filename
1020 )
1021 {
1022 if ((sym_data->shndx == SHN_UNDEF) && (strlen(sym_data->name))) {
1023 if (!r_flag) {
1024 if (R_flag) {
1025 if (archive_name != (char *)0)
1026 (void) printf(" %s:%s:%s\n",
1027 archive_name, filename,
1028 sym_data->name);
1029 else
1030 (void) printf(" %s:%s\n",
1031 filename, sym_data->name);
1032 }
1033 else
1034 (void) printf(" %s\n", sym_data->name);
1035 }
1036 else
1037 (void) printf(" %s:%s\n", filename, sym_data->name);
1038 }
1039 }
1040 #endif
1041
1042 /*
1043 * Print a symbol type representation suitable for the -p or -P formats.
1044 */
1045 static void
print_brief_sym_type(Elf * elf_file,unsigned int shstrndx,SYM * sym_data)1046 print_brief_sym_type(Elf *elf_file, unsigned int shstrndx, SYM *sym_data)
1047 {
1048 const char *sym_key = NULL;
1049
1050 if ((sym_data->shndx == SHN_UNDEF) && (strlen(sym_data->name)))
1051 sym_key = UNDEFINED;
1052 else if (sym_data->type == STT_SPARC_REGISTER) {
1053 switch (sym_data->bind) {
1054 case STB_LOCAL : sym_key = REG_LOCL;
1055 break;
1056 case STB_GLOBAL : sym_key = REG_GLOB;
1057 break;
1058 case STB_WEAK : sym_key = REG_WEAK;
1059 break;
1060 default : sym_key = REG_GLOB;
1061 break;
1062 }
1063 } else if (((sym_data->flags & FLG_SYM_SPECSEC) == 0) &&
1064 is_bss_section((int)sym_data->shndx, elf_file, shstrndx)) {
1065 switch (sym_data->bind) {
1066 case STB_LOCAL : sym_key = BSS_LOCL;
1067 break;
1068 case STB_GLOBAL : sym_key = BSS_GLOB;
1069 break;
1070 case STB_WEAK : sym_key = BSS_WEAK;
1071 break;
1072 default : sym_key = BSS_GLOB;
1073 break;
1074 }
1075
1076 } else {
1077 sym_key = lookup(sym_data->type, sym_data->bind);
1078 }
1079
1080 if (sym_key != NULL) {
1081 if (!l_flag)
1082 (void) printf("%c ", sym_key[0]);
1083 else
1084 (void) printf("%-3s", sym_key);
1085 } else {
1086 if (!l_flag)
1087 (void) printf("%-2d", sym_data->type);
1088 else
1089 (void) printf("%-3d", sym_data->type);
1090 }
1091 }
1092
1093 /*
1094 * -p flag specified
1095 */
1096 static void
print_with_pflag(int ndigits,Elf * elf_file,unsigned int shstrndx,SYM * sym_data,char * filename)1097 print_with_pflag(
1098 int ndigits,
1099 Elf *elf_file,
1100 unsigned int shstrndx,
1101 SYM *sym_data,
1102 char *filename
1103 )
1104 {
1105 const char * const fmt[] = {
1106 "%.*llu ", /* FMT_T_DEC */
1107 "0x%.*llx ", /* FMT_T_HEX */
1108 "0%.*llo " /* FMT_T_OCT */
1109 };
1110
1111 if (is_sym_print(sym_data) != 1)
1112 return;
1113 /*
1114 * -A header
1115 */
1116 if (A_flag != 0)
1117 (void) printf("%s", A_header);
1118
1119 /*
1120 * Symbol Value.
1121 * (hex/octal/decimal)
1122 */
1123 (void) printf(fmt[fmt_flag], ndigits, EC_ADDR(sym_data->value));
1124
1125
1126 /*
1127 * Symbol Type.
1128 */
1129 print_brief_sym_type(elf_file, shstrndx, sym_data);
1130
1131 if (!r_flag) {
1132 if (R_flag) {
1133 if (archive_name != (char *)0)
1134 (void) printf("%s:%s:%s\n", archive_name,
1135 filename, sym_data->name);
1136 else
1137 (void) printf("%s:%s\n", filename,
1138 sym_data->name);
1139 }
1140 else
1141 (void) printf("%s\n", sym_data->name);
1142 }
1143 else
1144 (void) printf("%s:%s\n", filename, sym_data->name);
1145 }
1146
1147 /*
1148 * -P flag specified
1149 */
1150 static void
print_with_Pflag(int ndigits,Elf * elf_file,unsigned int shstrndx,SYM * sym_data)1151 print_with_Pflag(
1152 int ndigits,
1153 Elf *elf_file,
1154 unsigned int shstrndx,
1155 SYM *sym_data
1156 )
1157 {
1158 #define SYM_LEN 10
1159 char sym_name[SYM_LEN+1];
1160 size_t len;
1161 const char * const fmt[] = {
1162 "%*llu %*llu \n", /* FMT_T_DEC */
1163 "%*llx %*llx \n", /* FMT_T_HEX */
1164 "%*llo %*llo \n" /* FMT_T_OCT */
1165 };
1166
1167 if (is_sym_print(sym_data) != 1)
1168 return;
1169 /*
1170 * -A header
1171 */
1172 if (A_flag != 0)
1173 (void) printf("%s", A_header);
1174
1175 /*
1176 * Symbol name
1177 */
1178 len = strlen(sym_data->name);
1179 if (len >= SYM_LEN)
1180 (void) printf("%s ", sym_data->name);
1181 else {
1182 (void) sprintf(sym_name, "%-10s", sym_data->name);
1183 (void) printf("%s ", sym_name);
1184 }
1185
1186 /*
1187 * Symbol Type.
1188 */
1189 print_brief_sym_type(elf_file, shstrndx, sym_data);
1190
1191 /*
1192 * Symbol Value & size
1193 * (hex/octal/decimal)
1194 */
1195 (void) printf(fmt[fmt_flag], ndigits, EC_ADDR(sym_data->value),
1196 ndigits, EC_XWORD(sym_data->size));
1197 }
1198
1199 /*
1200 * other flags specified
1201 */
1202 static void
print_with_otherflags(int ndigits,Elf * elf_file,unsigned int shstrndx,SYM * sym_data,char * filename)1203 print_with_otherflags(
1204 int ndigits,
1205 Elf *elf_file,
1206 unsigned int shstrndx,
1207 SYM *sym_data,
1208 char *filename
1209 )
1210 {
1211 const char * const fmt_value_size[] = {
1212 "%*llu|%*lld|", /* FMT_T_DEC */
1213 "0x%.*llx|0x%.*llx|", /* FMT_T_HEX */
1214 "0%.*llo|0%.*llo|" /* FMT_T_OCT */
1215 };
1216 const char * const fmt_int[] = {
1217 "%-5d", /* FMT_T_DEC */
1218 "%#-5x", /* FMT_T_HEX */
1219 "%#-5o" /* FMT_T_OCT */
1220 };
1221
1222 if (is_sym_print(sym_data) != 1)
1223 return;
1224 (void) printf("%s", A_header);
1225 (void) printf("[%d]\t|", sym_data->indx);
1226 (void) printf(fmt_value_size[fmt_flag], ndigits,
1227 EC_ADDR(sym_data->value), ndigits, EC_XWORD(sym_data->size));
1228
1229 switch (sym_data->type) {
1230 case STT_NOTYPE:(void) printf("%-5s", "NOTY"); break;
1231 case STT_OBJECT:(void) printf("%-5s", "OBJT"); break;
1232 case STT_FUNC: (void) printf("%-5s", "FUNC"); break;
1233 case STT_SECTION:(void) printf("%-5s", "SECT"); break;
1234 case STT_FILE: (void) printf("%-5s", "FILE"); break;
1235 case STT_COMMON: (void) printf("%-5s", "COMM"); break;
1236 case STT_TLS: (void) printf("%-5s", "TLS "); break;
1237 case STT_SPARC_REGISTER: (void) printf("%-5s", "REGI"); break;
1238 default:
1239 (void) printf(fmt_int[fmt_flag], sym_data->type);
1240 }
1241 (void) printf("|");
1242 switch (sym_data->bind) {
1243 case STB_LOCAL: (void) printf("%-5s", "LOCL"); break;
1244 case STB_GLOBAL:(void) printf("%-5s", "GLOB"); break;
1245 case STB_WEAK: (void) printf("%-5s", "WEAK"); break;
1246 default:
1247 (void) printf("%-5d", sym_data->bind);
1248 (void) printf(fmt_int[fmt_flag], sym_data->bind);
1249 }
1250 (void) printf("|");
1251 (void) printf(fmt_int[fmt_flag], sym_data->other);
1252 (void) printf("|");
1253
1254 if (sym_data->shndx == SHN_UNDEF) {
1255 if (!s_flag)
1256 (void) printf("%-7s", "UNDEF");
1257 else
1258 (void) printf("%-14s", "UNDEF");
1259 } else if (sym_data->shndx == SHN_SUNW_IGNORE) {
1260 if (!s_flag)
1261 (void) printf("%-7s", "IGNORE");
1262 else
1263 (void) printf("%-14s", "IGNORE");
1264 } else if ((sym_data->flags & FLG_SYM_SPECSEC) &&
1265 (sym_data->shndx == SHN_ABS)) {
1266 if (!s_flag)
1267 (void) printf("%-7s", "ABS");
1268 else
1269 (void) printf("%-14s", "ABS");
1270 } else if ((sym_data->flags & FLG_SYM_SPECSEC) &&
1271 (sym_data->shndx == SHN_COMMON)) {
1272 if (!s_flag)
1273 (void) printf("%-7s", "COMMON");
1274 else
1275 (void) printf("%-14s", "COMMON");
1276 } else {
1277 if (s_flag) {
1278 Elf_Scn *scn = elf_getscn(elf_file, sym_data->shndx);
1279 GElf_Shdr shdr;
1280
1281 if ((gelf_getshdr(scn, &shdr) != 0) &&
1282 (shdr.sh_name != 0)) {
1283 (void) printf("%-14s",
1284 (char *)elf_strptr(elf_file,
1285 shstrndx, shdr.sh_name));
1286 } else {
1287 (void) printf("%-14d", sym_data->shndx);
1288 }
1289 } else {
1290 (void) printf("%-7d", sym_data->shndx);
1291 }
1292 }
1293 (void) printf("|");
1294 if (!r_flag) {
1295 if (R_flag) {
1296 if (archive_name != (char *)0)
1297 (void) printf("%s:%s:%s\n", archive_name,
1298 filename, sym_data->name);
1299 else
1300 (void) printf("%s:%s\n", filename,
1301 sym_data->name);
1302 }
1303 else
1304 (void) printf("%s\n", sym_data->name);
1305 }
1306 else
1307 (void) printf("%s:%s\n", filename, sym_data->name);
1308 }
1309
1310 /*
1311 * C++ name demangling supporting routines
1312 */
1313 static const char *ctor_str = "static constructor function for %s";
1314 static const char *dtor_str = "static destructor function for %s";
1315 static const char *ptbl_str = "pointer to the virtual table vector for %s";
1316 static const char *vtbl_str = "virtual table for %s";
1317
1318 /*
1319 * alloc memory and create name in necessary format.
1320 * Return name string
1321 */
1322 static char *
FormatName(char * OldName,const char * NewName)1323 FormatName(char *OldName, const char *NewName)
1324 {
1325 char *s = p_flag ?
1326 "%s\n [%s]" :
1327 "%s\n\t\t\t\t\t\t [%s]";
1328 size_t length = strlen(s)+strlen(NewName)+strlen(OldName)-3;
1329 char *hold = OldName;
1330 OldName = malloc(length);
1331 /*LINTED*/
1332 (void) snprintf(OldName, length, s, NewName, hold);
1333 return (OldName);
1334 }
1335
1336
1337 /*
1338 * Return 1 when s is an exotic name, 0 otherwise. s remains unchanged,
1339 * the exotic name, if exists, is saved in d_buf.
1340 */
1341 static int
exotic(const char * in_str)1342 exotic(const char *in_str)
1343 {
1344 static char *buff = 0;
1345 static size_t buf_size;
1346
1347 size_t sym_len = strlen(in_str) + 1;
1348 int tag = 0;
1349 char *s;
1350
1351 /*
1352 * We will need to modify the symbol (in_str) as we are analyzing it,
1353 * so copy it into a buffer so that we can play around with it.
1354 */
1355 if (buff == NULL) {
1356 buff = malloc(DEF_MAX_SYM_SIZE);
1357 buf_size = DEF_MAX_SYM_SIZE;
1358 }
1359
1360 if (sym_len > buf_size) {
1361 if (buff)
1362 free(buff);
1363 buff = malloc(sym_len);
1364 buf_size = sym_len;
1365 }
1366
1367 if (buff == NULL) {
1368 (void) fprintf(stderr, gettext(
1369 "%s: cannot allocate memory\n"), prog_name);
1370 exit(NOALLOC);
1371 }
1372 s = strcpy(buff, in_str);
1373
1374
1375 if (strncmp(s, "__sti__", 7) == 0) {
1376 s += 7; tag = 1;
1377 parse_fn_and_print(ctor_str, s);
1378 } else if (strncmp(s, "__std__", 7) == 0) {
1379 s += 7; tag = 1;
1380 parse_fn_and_print(dtor_str, s);
1381 } else if (strncmp(s, "__vtbl__", 8) == 0) {
1382 s += 8; tag = 1;
1383 parsename(s);
1384 (void) sprintf(d_buf, vtbl_str, p_buf);
1385 } else if (strncmp(s, "__ptbl_vec__", 12) == 0) {
1386 s += 12; tag = 1;
1387 parse_fn_and_print(ptbl_str, s);
1388 }
1389 return (tag);
1390 }
1391
1392 void
parsename(char * s)1393 parsename(char *s)
1394 {
1395 register int len;
1396 char c, *orig = s;
1397 *p_buf = '\0';
1398 (void) strcat(p_buf, "class ");
1399 while (isdigit(*s)) s++;
1400 c = *s;
1401 *s = '\0';
1402 len = atoi(orig);
1403 *s = c;
1404 if (*(s+len) == '\0') { /* only one class name */
1405 (void) strcat(p_buf, s);
1406 return;
1407 } else
1408 { /* two classname %drootname__%dchildname */
1409 char *root, *child, *child_len_p;
1410 int child_len;
1411 root = s;
1412 child = s + len + 2;
1413 child_len_p = child;
1414 if (!isdigit(*child)) {
1415 /* ptbl file name */
1416 /* %drootname__%filename */
1417 /* kludge for getting rid of '_' in file name */
1418 char *p;
1419 c = *(root + len);
1420 *(root + len) = '\0';
1421 (void) strcat(p_buf, root);
1422 *(root + len) = c;
1423 (void) strcat(p_buf, " in ");
1424 for (p = child; *p != '_'; ++p)
1425 ;
1426 c = *p;
1427 *p = '.';
1428 (void) strcat(p_buf, child);
1429 *p = c;
1430 return;
1431 }
1432
1433 while (isdigit(*child))
1434 child++;
1435 c = *child;
1436 *child = '\0';
1437 child_len = atoi(child_len_p);
1438 *child = c;
1439 if (*(child + child_len) == '\0') {
1440 (void) strcat(p_buf, child);
1441 (void) strcat(p_buf, " derived from ");
1442 c = *(root + len);
1443 *(root + len) = '\0';
1444 (void) strcat(p_buf, root);
1445 *(root + len) = c;
1446 return;
1447 } else {
1448 /* %drootname__%dchildname__filename */
1449 /* kludge for getting rid of '_' in file name */
1450 char *p;
1451 c = *(child + child_len);
1452 *(child + child_len) = '\0';
1453 (void) strcat(p_buf, child);
1454 *(child+child_len) = c;
1455 (void) strcat(p_buf, " derived from ");
1456 c = *(root + len);
1457 *(root + len) = '\0';
1458 (void) strcat(p_buf, root);
1459 *(root + len) = c;
1460 (void) strcat(p_buf, " in ");
1461 for (p = child + child_len + 2; *p != '_'; ++p)
1462 ;
1463 c = *p;
1464 *p = '.';
1465 (void) strcat(p_buf, child + child_len + 2);
1466 *p = c;
1467 return;
1468 }
1469 }
1470 }
1471
1472 void
parse_fn_and_print(const char * str,char * s)1473 parse_fn_and_print(const char *str, char *s)
1474 {
1475 char c, *p1, *p2;
1476 int yes = 1;
1477
1478 if ((p1 = p2 = strstr(s, "_c_")) == NULL)
1479 if ((p1 = p2 = strstr(s, "_C_")) == NULL)
1480 if ((p1 = p2 = strstr(s, "_cc_")) == NULL)
1481 if ((p1 = p2 = strstr(s, "_cxx_")) == NULL)
1482 if ((p1 = p2 = strstr(s, "_h_")) ==
1483 NULL)
1484 yes = 0;
1485 else
1486 p2 += 2;
1487 else
1488 p2 += 4;
1489 else
1490 p2 += 3;
1491 else
1492 p2 += 2;
1493 else
1494 p2 += 2;
1495
1496 if (yes) {
1497 *p1 = '.';
1498 c = *p2;
1499 *p2 = '\0';
1500 }
1501
1502 for (s = p1; *s != '_'; --s)
1503 ;
1504 ++s;
1505
1506 (void) sprintf(d_buf, str, s);
1507
1508 if (yes) {
1509 *p1 = '_';
1510 *p2 = c;
1511 }
1512 }
1513