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