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