xref: /illumos-gate/usr/src/cmd/sgs/libconv/common/symbols.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
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 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 /*
29  * String conversion routines for symbol attributes.
30  */
31 #include	<stdio.h>
32 #include	<demangle.h>
33 #include	"_conv.h"
34 #include	"symbols_msg.h"
35 #include	<sys/elf_SPARC.h>
36 
37 static const char vis_types[4] = {
38 	'D',	/* STV_DEFAULT */
39 	'I',	/* STV_INTERNAL */
40 	'H',	/* STV_HIDDEN */
41 	'P'	/* STV_PROTECTED */
42 	};
43 
44 const char *
45 conv_sym_stother(uchar_t stother)
46 {
47 	uint_t	vis = ELF_ST_VISIBILITY(stother);
48 	static char	string[STRSIZE];
49 	uint_t	ndx = 0;
50 
51 	string[ndx++] = vis_types[vis];
52 	/*
53 	 * If unkown bits are present in stother - throw out a '?'
54 	 */
55 	if (stother & ~MSK_SYM_VISIBILITY)
56 		string[ndx++] = '?';
57 
58 	string[ndx++] = '\0';
59 
60 	return (string);
61 }
62 
63 static const Msg types[] = {
64 	MSG_STT_NOTYPE,		MSG_STT_OBJECT,		MSG_STT_FUNC,
65 	MSG_STT_SECTION,	MSG_STT_FILE,		MSG_STT_COMMON,
66 	MSG_STT_TLS
67 };
68 
69 const char *
70 conv_info_type_str(ushort_t mach, uchar_t type)
71 {
72 	static char	string[STRSIZE] = { '\0' };
73 
74 
75 	if (type < STT_NUM)
76 		return (MSG_ORIG(types[type]));
77 	else if (((mach == EM_SPARC) || (mach == EM_SPARC32PLUS) ||
78 	    (mach == EM_SPARCV9)) && (type == STT_SPARC_REGISTER))
79 		return (MSG_ORIG(MSG_STT_REGISTER));
80 	else
81 		return (conv_invalid_str(string, STRSIZE, type, 0));
82 }
83 
84 static const Msg binds[] = {
85 	MSG_STB_LOCAL,		MSG_STB_GLOBAL,		MSG_STB_WEAK
86 };
87 
88 const char *
89 conv_info_bind_str(uchar_t bind)
90 {
91 	static char	string[STRSIZE] = { '\0' };
92 
93 	if (bind >= STB_NUM)
94 		return (conv_invalid_str(string, STRSIZE, bind, 0));
95 	else
96 		return (MSG_ORIG(binds[bind]));
97 }
98 
99 const char *
100 conv_shndx_str(ushort_t shndx)
101 {
102 	static	char	string[STRSIZE] = { '\0' };
103 
104 	if (shndx == SHN_UNDEF)
105 		return (MSG_ORIG(MSG_SHN_UNDEF));
106 	else if (shndx == SHN_SUNW_IGNORE)
107 		return (MSG_ORIG(MSG_SHN_SUNW_IGNORE));
108 	else if (shndx == SHN_ABS)
109 		return (MSG_ORIG(MSG_SHN_ABS));
110 	else if (shndx == SHN_COMMON)
111 		return (MSG_ORIG(MSG_SHN_COMMON));
112 	else if (shndx == SHN_AFTER)
113 		return (MSG_ORIG(MSG_SHN_AFTER));
114 	else if (shndx == SHN_BEFORE)
115 		return (MSG_ORIG(MSG_SHN_BEFORE));
116 	else if (shndx == SHN_XINDEX)
117 		return (MSG_ORIG(MSG_SHN_XINDEX));
118 	else
119 		return (conv_invalid_str(string, STRSIZE, shndx, 1));
120 }
121 
122 const char *
123 conv_sym_value_str(ushort_t mach, uint_t type, uint64_t value)
124 {
125 	static char	string[STRSIZE64] = { '\0' };
126 	const char	*fmt;
127 
128 	if (((mach == EM_SPARC) || (mach == EM_SPARC32PLUS) ||
129 	    (mach == EM_SPARCV9)) && (type == STT_SPARC_REGISTER))
130 		return (conv_sym_SPARC_value_str(value));
131 
132 	/*
133 	 * Should obtain the elf class rather than relying on e_machine here...
134 	 */
135 	if (mach == EM_SPARCV9)
136 		fmt = MSG_ORIG(MSG_FMT_VAL_64);
137 	else
138 		fmt = MSG_ORIG(MSG_FMT_VAL);
139 
140 	(void) sprintf(string, fmt, EC_XWORD(value));
141 	return (string);
142 }
143 
144 /*
145  * Demangle C++ symbols.
146  *
147  * This routine acts as a generic routine for use by liblddbg (and hence tools
148  * like elfdump(1) and pvs(1)), ld(1) and ld.so.1(1).
149  *
150  * The C++ ABI-2 places no limits on symbol names, thus when demangling a name
151  * it's possible the buffer won't be big enough (DEMANGLE_ESPACE) so here we
152  * try to allocate bigger buffers.  However, we place a limit on this buffer
153  * size for fear of a C++ error sending us into an infinit loop.
154  *
155  * NOTE. we create and use a common buffer for use by cplus_demangle(), thus
156  * each call to this routine will override the contents of any existing call.
157  * Normally this is sufficient for typical error diagnostics referencing one
158  * symbol.  For those diagnostics using more than one symbol name, all but the
159  * last name must be copied to a temporary buffer (regardless of whether
160  * demangling occurred, as the process of attempting to demangle may damage the
161  * buffer).  One model is:
162  *
163  *	if ((_name1 = demangle(name1)) != name1) {
164  *		char *	__name1 = alloca(strlen(_name1) + 1);
165  *		(void) strcpy(__name1, _name1);
166  *		name1 = (const char *)__name1;
167  *	}
168  *	name2 = demangle(name2);
169  *	eprintf(format, name1, name2);
170  */
171 #define	SYM_MAX	1000
172 
173 const char *
174 conv_sym_dem(const char *name)
175 {
176 	static char	_str[SYM_MAX], *str = _str;
177 	static size_t	size = SYM_MAX;
178 	static int	again = 1;
179 	static int	(*fptr)() = 0;
180 	int		error;
181 
182 	if (str == 0)
183 		return (name);
184 
185 	/*
186 	 * If we haven't located the demangler yet try now (we do this rather
187 	 * than maintain a static dependency on libdemangle as it's part of an
188 	 * optional package).  Null the str element out to reject any other
189 	 * callers until this operation is complete - under ld.so.1 we can get
190 	 * into serious recursion without this.
191 	 */
192 	if (fptr == 0) {
193 		void	*hdl;
194 
195 		str = 0;
196 		if (!(hdl = dlopen(MSG_ORIG(MSG_DEM_LIB), RTLD_LAZY)) ||
197 		    !(fptr = (int (*)())dlsym(hdl, MSG_ORIG(MSG_DEM_SYM))))
198 			return (name);
199 		str = _str;
200 	}
201 
202 	if ((error = (*fptr)(name, str, size)) == 0)
203 		return ((const char *)str);
204 
205 	while ((error == DEMANGLE_ESPACE) && again) {
206 		char	*_str;
207 		size_t	_size = size;
208 
209 		/*
210 		 * If we haven't allocated our maximum try incrementing the
211 		 * present buffer size. Use malloc() rather than realloc() so
212 		 * that we at least have the old buffer on failure.
213 		 */
214 		if (((_size += SYM_MAX) > (SYM_MAX * 4)) ||
215 		    ((_str = malloc(_size)) == 0)) {
216 			again = 0;
217 			break;
218 		}
219 		if (size != SYM_MAX) {
220 			free(str);
221 		}
222 		str = _str;
223 		size = _size;
224 
225 		if ((error = (*fptr)(name, str, size)) == 0)
226 			return ((const char *)str);
227 	}
228 	return (name);
229 }
230