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