10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
23*574Sseizo  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate /*
290Sstevel@tonic-gate  * String conversion routines for symbol attributes.
300Sstevel@tonic-gate  */
310Sstevel@tonic-gate #include	<stdio.h>
320Sstevel@tonic-gate #include	<demangle.h>
330Sstevel@tonic-gate #include	"_conv.h"
340Sstevel@tonic-gate #include	"symbols_msg.h"
350Sstevel@tonic-gate #include	<sys/elf_SPARC.h>
36*574Sseizo #include	<sys/elf_amd64.h>
370Sstevel@tonic-gate 
380Sstevel@tonic-gate static const char vis_types[4] = {
390Sstevel@tonic-gate 	'D',	/* STV_DEFAULT */
400Sstevel@tonic-gate 	'I',	/* STV_INTERNAL */
410Sstevel@tonic-gate 	'H',	/* STV_HIDDEN */
420Sstevel@tonic-gate 	'P'	/* STV_PROTECTED */
430Sstevel@tonic-gate 	};
440Sstevel@tonic-gate 
450Sstevel@tonic-gate const char *
460Sstevel@tonic-gate conv_sym_stother(uchar_t stother)
470Sstevel@tonic-gate {
480Sstevel@tonic-gate 	uint_t	vis = ELF_ST_VISIBILITY(stother);
490Sstevel@tonic-gate 	static char	string[STRSIZE];
500Sstevel@tonic-gate 	uint_t	ndx = 0;
510Sstevel@tonic-gate 
520Sstevel@tonic-gate 	string[ndx++] = vis_types[vis];
530Sstevel@tonic-gate 	/*
540Sstevel@tonic-gate 	 * If unkown bits are present in stother - throw out a '?'
550Sstevel@tonic-gate 	 */
560Sstevel@tonic-gate 	if (stother & ~MSK_SYM_VISIBILITY)
570Sstevel@tonic-gate 		string[ndx++] = '?';
580Sstevel@tonic-gate 
590Sstevel@tonic-gate 	string[ndx++] = '\0';
600Sstevel@tonic-gate 
610Sstevel@tonic-gate 	return (string);
620Sstevel@tonic-gate }
630Sstevel@tonic-gate 
640Sstevel@tonic-gate static const Msg types[] = {
650Sstevel@tonic-gate 	MSG_STT_NOTYPE,		MSG_STT_OBJECT,		MSG_STT_FUNC,
660Sstevel@tonic-gate 	MSG_STT_SECTION,	MSG_STT_FILE,		MSG_STT_COMMON,
670Sstevel@tonic-gate 	MSG_STT_TLS
680Sstevel@tonic-gate };
690Sstevel@tonic-gate 
700Sstevel@tonic-gate const char *
710Sstevel@tonic-gate conv_info_type_str(ushort_t mach, uchar_t type)
720Sstevel@tonic-gate {
730Sstevel@tonic-gate 	static char	string[STRSIZE] = { '\0' };
740Sstevel@tonic-gate 
750Sstevel@tonic-gate 
760Sstevel@tonic-gate 	if (type < STT_NUM)
770Sstevel@tonic-gate 		return (MSG_ORIG(types[type]));
780Sstevel@tonic-gate 	else if (((mach == EM_SPARC) || (mach == EM_SPARC32PLUS) ||
790Sstevel@tonic-gate 	    (mach == EM_SPARCV9)) && (type == STT_SPARC_REGISTER))
800Sstevel@tonic-gate 		return (MSG_ORIG(MSG_STT_REGISTER));
810Sstevel@tonic-gate 	else
820Sstevel@tonic-gate 		return (conv_invalid_str(string, STRSIZE, type, 0));
830Sstevel@tonic-gate }
840Sstevel@tonic-gate 
850Sstevel@tonic-gate static const Msg binds[] = {
860Sstevel@tonic-gate 	MSG_STB_LOCAL,		MSG_STB_GLOBAL,		MSG_STB_WEAK
870Sstevel@tonic-gate };
880Sstevel@tonic-gate 
890Sstevel@tonic-gate const char *
900Sstevel@tonic-gate conv_info_bind_str(uchar_t bind)
910Sstevel@tonic-gate {
920Sstevel@tonic-gate 	static char	string[STRSIZE] = { '\0' };
930Sstevel@tonic-gate 
940Sstevel@tonic-gate 	if (bind >= STB_NUM)
950Sstevel@tonic-gate 		return (conv_invalid_str(string, STRSIZE, bind, 0));
960Sstevel@tonic-gate 	else
970Sstevel@tonic-gate 		return (MSG_ORIG(binds[bind]));
980Sstevel@tonic-gate }
990Sstevel@tonic-gate 
1000Sstevel@tonic-gate const char *
1010Sstevel@tonic-gate conv_shndx_str(ushort_t shndx)
1020Sstevel@tonic-gate {
1030Sstevel@tonic-gate 	static	char	string[STRSIZE] = { '\0' };
1040Sstevel@tonic-gate 
1050Sstevel@tonic-gate 	if (shndx == SHN_UNDEF)
1060Sstevel@tonic-gate 		return (MSG_ORIG(MSG_SHN_UNDEF));
1070Sstevel@tonic-gate 	else if (shndx == SHN_SUNW_IGNORE)
1080Sstevel@tonic-gate 		return (MSG_ORIG(MSG_SHN_SUNW_IGNORE));
1090Sstevel@tonic-gate 	else if (shndx == SHN_ABS)
1100Sstevel@tonic-gate 		return (MSG_ORIG(MSG_SHN_ABS));
1110Sstevel@tonic-gate 	else if (shndx == SHN_COMMON)
1120Sstevel@tonic-gate 		return (MSG_ORIG(MSG_SHN_COMMON));
113*574Sseizo 	else if (shndx == SHN_X86_64_LCOMMON)
114*574Sseizo 		return (MSG_ORIG(MSG_SHN_X86_64_LCOMMON));
1150Sstevel@tonic-gate 	else if (shndx == SHN_AFTER)
1160Sstevel@tonic-gate 		return (MSG_ORIG(MSG_SHN_AFTER));
1170Sstevel@tonic-gate 	else if (shndx == SHN_BEFORE)
1180Sstevel@tonic-gate 		return (MSG_ORIG(MSG_SHN_BEFORE));
1190Sstevel@tonic-gate 	else if (shndx == SHN_XINDEX)
1200Sstevel@tonic-gate 		return (MSG_ORIG(MSG_SHN_XINDEX));
1210Sstevel@tonic-gate 	else
1220Sstevel@tonic-gate 		return (conv_invalid_str(string, STRSIZE, shndx, 1));
1230Sstevel@tonic-gate }
1240Sstevel@tonic-gate 
1250Sstevel@tonic-gate const char *
1260Sstevel@tonic-gate conv_sym_value_str(ushort_t mach, uint_t type, uint64_t value)
1270Sstevel@tonic-gate {
1280Sstevel@tonic-gate 	static char	string[STRSIZE64] = { '\0' };
1290Sstevel@tonic-gate 	const char	*fmt;
1300Sstevel@tonic-gate 
1310Sstevel@tonic-gate 	if (((mach == EM_SPARC) || (mach == EM_SPARC32PLUS) ||
1320Sstevel@tonic-gate 	    (mach == EM_SPARCV9)) && (type == STT_SPARC_REGISTER))
1330Sstevel@tonic-gate 		return (conv_sym_SPARC_value_str(value));
1340Sstevel@tonic-gate 
1350Sstevel@tonic-gate 	/*
1360Sstevel@tonic-gate 	 * Should obtain the elf class rather than relying on e_machine here...
1370Sstevel@tonic-gate 	 */
1380Sstevel@tonic-gate 	if (mach == EM_SPARCV9)
1390Sstevel@tonic-gate 		fmt = MSG_ORIG(MSG_FMT_VAL_64);
1400Sstevel@tonic-gate 	else
1410Sstevel@tonic-gate 		fmt = MSG_ORIG(MSG_FMT_VAL);
1420Sstevel@tonic-gate 
1430Sstevel@tonic-gate 	(void) sprintf(string, fmt, EC_XWORD(value));
1440Sstevel@tonic-gate 	return (string);
1450Sstevel@tonic-gate }
1460Sstevel@tonic-gate 
1470Sstevel@tonic-gate /*
1480Sstevel@tonic-gate  * Demangle C++ symbols.
1490Sstevel@tonic-gate  *
1500Sstevel@tonic-gate  * This routine acts as a generic routine for use by liblddbg (and hence tools
1510Sstevel@tonic-gate  * like elfdump(1) and pvs(1)), ld(1) and ld.so.1(1).
1520Sstevel@tonic-gate  *
1530Sstevel@tonic-gate  * The C++ ABI-2 places no limits on symbol names, thus when demangling a name
1540Sstevel@tonic-gate  * it's possible the buffer won't be big enough (DEMANGLE_ESPACE) so here we
1550Sstevel@tonic-gate  * try to allocate bigger buffers.  However, we place a limit on this buffer
1560Sstevel@tonic-gate  * size for fear of a C++ error sending us into an infinit loop.
1570Sstevel@tonic-gate  *
1580Sstevel@tonic-gate  * NOTE. we create and use a common buffer for use by cplus_demangle(), thus
1590Sstevel@tonic-gate  * each call to this routine will override the contents of any existing call.
1600Sstevel@tonic-gate  * Normally this is sufficient for typical error diagnostics referencing one
1610Sstevel@tonic-gate  * symbol.  For those diagnostics using more than one symbol name, all but the
1620Sstevel@tonic-gate  * last name must be copied to a temporary buffer (regardless of whether
1630Sstevel@tonic-gate  * demangling occurred, as the process of attempting to demangle may damage the
1640Sstevel@tonic-gate  * buffer).  One model is:
1650Sstevel@tonic-gate  *
1660Sstevel@tonic-gate  *	if ((_name1 = demangle(name1)) != name1) {
1670Sstevel@tonic-gate  *		char *	__name1 = alloca(strlen(_name1) + 1);
1680Sstevel@tonic-gate  *		(void) strcpy(__name1, _name1);
1690Sstevel@tonic-gate  *		name1 = (const char *)__name1;
1700Sstevel@tonic-gate  *	}
1710Sstevel@tonic-gate  *	name2 = demangle(name2);
1720Sstevel@tonic-gate  *	eprintf(format, name1, name2);
1730Sstevel@tonic-gate  */
1740Sstevel@tonic-gate #define	SYM_MAX	1000
1750Sstevel@tonic-gate 
1760Sstevel@tonic-gate const char *
1770Sstevel@tonic-gate conv_sym_dem(const char *name)
1780Sstevel@tonic-gate {
1790Sstevel@tonic-gate 	static char	_str[SYM_MAX], *str = _str;
1800Sstevel@tonic-gate 	static size_t	size = SYM_MAX;
1810Sstevel@tonic-gate 	static int	again = 1;
1820Sstevel@tonic-gate 	static int	(*fptr)() = 0;
1830Sstevel@tonic-gate 	int		error;
1840Sstevel@tonic-gate 
1850Sstevel@tonic-gate 	if (str == 0)
1860Sstevel@tonic-gate 		return (name);
1870Sstevel@tonic-gate 
1880Sstevel@tonic-gate 	/*
1890Sstevel@tonic-gate 	 * If we haven't located the demangler yet try now (we do this rather
1900Sstevel@tonic-gate 	 * than maintain a static dependency on libdemangle as it's part of an
1910Sstevel@tonic-gate 	 * optional package).  Null the str element out to reject any other
1920Sstevel@tonic-gate 	 * callers until this operation is complete - under ld.so.1 we can get
1930Sstevel@tonic-gate 	 * into serious recursion without this.
1940Sstevel@tonic-gate 	 */
1950Sstevel@tonic-gate 	if (fptr == 0) {
1960Sstevel@tonic-gate 		void	*hdl;
1970Sstevel@tonic-gate 
1980Sstevel@tonic-gate 		str = 0;
1990Sstevel@tonic-gate 		if (!(hdl = dlopen(MSG_ORIG(MSG_DEM_LIB), RTLD_LAZY)) ||
2000Sstevel@tonic-gate 		    !(fptr = (int (*)())dlsym(hdl, MSG_ORIG(MSG_DEM_SYM))))
2010Sstevel@tonic-gate 			return (name);
2020Sstevel@tonic-gate 		str = _str;
2030Sstevel@tonic-gate 	}
2040Sstevel@tonic-gate 
2050Sstevel@tonic-gate 	if ((error = (*fptr)(name, str, size)) == 0)
2060Sstevel@tonic-gate 		return ((const char *)str);
2070Sstevel@tonic-gate 
2080Sstevel@tonic-gate 	while ((error == DEMANGLE_ESPACE) && again) {
2090Sstevel@tonic-gate 		char	*_str;
2100Sstevel@tonic-gate 		size_t	_size = size;
2110Sstevel@tonic-gate 
2120Sstevel@tonic-gate 		/*
2130Sstevel@tonic-gate 		 * If we haven't allocated our maximum try incrementing the
2140Sstevel@tonic-gate 		 * present buffer size. Use malloc() rather than realloc() so
2150Sstevel@tonic-gate 		 * that we at least have the old buffer on failure.
2160Sstevel@tonic-gate 		 */
2170Sstevel@tonic-gate 		if (((_size += SYM_MAX) > (SYM_MAX * 4)) ||
2180Sstevel@tonic-gate 		    ((_str = malloc(_size)) == 0)) {
2190Sstevel@tonic-gate 			again = 0;
2200Sstevel@tonic-gate 			break;
2210Sstevel@tonic-gate 		}
2220Sstevel@tonic-gate 		if (size != SYM_MAX) {
2230Sstevel@tonic-gate 			free(str);
2240Sstevel@tonic-gate 		}
2250Sstevel@tonic-gate 		str = _str;
2260Sstevel@tonic-gate 		size = _size;
2270Sstevel@tonic-gate 
2280Sstevel@tonic-gate 		if ((error = (*fptr)(name, str, size)) == 0)
2290Sstevel@tonic-gate 			return ((const char *)str);
2300Sstevel@tonic-gate 	}
2310Sstevel@tonic-gate 	return (name);
2320Sstevel@tonic-gate }
233