xref: /onnv-gate/usr/src/cmd/sgs/libconv/common/demangle.c (revision 1618:8c9a4f31d225)
1*1618Srie /*
2*1618Srie  * CDDL HEADER START
3*1618Srie  *
4*1618Srie  * The contents of this file are subject to the terms of the
5*1618Srie  * Common Development and Distribution License (the "License").
6*1618Srie  * You may not use this file except in compliance with the License.
7*1618Srie  *
8*1618Srie  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*1618Srie  * or http://www.opensolaris.org/os/licensing.
10*1618Srie  * See the License for the specific language governing permissions
11*1618Srie  * and limitations under the License.
12*1618Srie  *
13*1618Srie  * When distributing Covered Code, include this CDDL HEADER in each
14*1618Srie  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*1618Srie  * If applicable, add the following below this CDDL HEADER, with the
16*1618Srie  * fields enclosed by brackets "[]" replaced with your own identifying
17*1618Srie  * information: Portions Copyright [yyyy] [name of copyright owner]
18*1618Srie  *
19*1618Srie  * CDDL HEADER END
20*1618Srie  */
21*1618Srie 
22*1618Srie /*
23*1618Srie  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24*1618Srie  * Use is subject to license terms.
25*1618Srie  */
26*1618Srie #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*1618Srie 
28*1618Srie #include	<stdio.h>
29*1618Srie #include	<demangle.h>
30*1618Srie #include	"_conv.h"
31*1618Srie #include	"demangle_msg.h"
32*1618Srie 
33*1618Srie /*
34*1618Srie  * Demangle C++ symbols.
35*1618Srie  *
36*1618Srie  * This routine acts as a generic routine for use by liblddbg (and hence tools
37*1618Srie  * like elfdump(1) and pvs(1)), ld(1) and ld.so.1(1).
38*1618Srie  *
39*1618Srie  * The C++ ABI-2 places no limits on symbol names, thus when demangling a name
40*1618Srie  * it's possible the buffer won't be big enough (DEMANGLE_ESPACE) so here we
41*1618Srie  * try to allocate bigger buffers.  However, we place a limit on this buffer
42*1618Srie  * size for fear of a C++ error sending us into an infinit loop.
43*1618Srie  *
44*1618Srie  * NOTE. we create and use a common buffer for use by cplus_demangle(), thus
45*1618Srie  * each call to this routine will override the contents of any existing call.
46*1618Srie  * Normally this is sufficient for typical error diagnostics referencing one
47*1618Srie  * symbol.  For those diagnostics using more than one symbol name, all but the
48*1618Srie  * last name must be copied to a temporary buffer (regardless of whether
49*1618Srie  * demangling occurred, as the process of attempting to demangle may damage the
50*1618Srie  * buffer).  One model is:
51*1618Srie  *
52*1618Srie  *	if ((_name1 = demangle(name1)) != name1) {
53*1618Srie  *		char *	__name1 = alloca(strlen(_name1) + 1);
54*1618Srie  *		(void) strcpy(__name1, _name1);
55*1618Srie  *		name1 = (const char *)__name1;
56*1618Srie  *	}
57*1618Srie  *	name2 = demangle(name2);
58*1618Srie  *	eprintf(format, name1, name2);
59*1618Srie  */
60*1618Srie #define	SYM_MAX	1000
61*1618Srie 
62*1618Srie const char *
63*1618Srie conv_demangle_name(const char *name)
64*1618Srie {
65*1618Srie 	static char	_str[SYM_MAX], *str = _str;
66*1618Srie 	static size_t	size = SYM_MAX;
67*1618Srie 	static int	again = 1;
68*1618Srie 	static int	(*fptr)() = 0;
69*1618Srie 	int		error;
70*1618Srie 
71*1618Srie 	if (str == 0)
72*1618Srie 		return (name);
73*1618Srie 
74*1618Srie 	/*
75*1618Srie 	 * If we haven't located the demangler yet try now (we do this rather
76*1618Srie 	 * than maintain a static dependency on libdemangle as it's part of an
77*1618Srie 	 * optional package).  Null the str element out to reject any other
78*1618Srie 	 * callers until this operation is complete - under ld.so.1 we can get
79*1618Srie 	 * into serious recursion without this.
80*1618Srie 	 */
81*1618Srie 	if (fptr == 0) {
82*1618Srie 		void	*hdl;
83*1618Srie 
84*1618Srie 		str = 0;
85*1618Srie 		if (!(hdl = dlopen(MSG_ORIG(MSG_DEM_LIB), RTLD_LAZY)) ||
86*1618Srie 		    !(fptr = (int (*)())dlsym(hdl, MSG_ORIG(MSG_DEM_SYM))))
87*1618Srie 			return (name);
88*1618Srie 		str = _str;
89*1618Srie 	}
90*1618Srie 
91*1618Srie 	if ((error = (*fptr)(name, str, size)) == 0)
92*1618Srie 		return ((const char *)str);
93*1618Srie 
94*1618Srie 	while ((error == DEMANGLE_ESPACE) && again) {
95*1618Srie 		char	*_str;
96*1618Srie 		size_t	_size = size;
97*1618Srie 
98*1618Srie 		/*
99*1618Srie 		 * If we haven't allocated our maximum try incrementing the
100*1618Srie 		 * present buffer size. Use malloc() rather than realloc() so
101*1618Srie 		 * that we at least have the old buffer on failure.
102*1618Srie 		 */
103*1618Srie 		if (((_size += SYM_MAX) > (SYM_MAX * 4)) ||
104*1618Srie 		    ((_str = malloc(_size)) == 0)) {
105*1618Srie 			again = 0;
106*1618Srie 			break;
107*1618Srie 		}
108*1618Srie 		if (size != SYM_MAX) {
109*1618Srie 			free(str);
110*1618Srie 		}
111*1618Srie 		str = _str;
112*1618Srie 		size = _size;
113*1618Srie 
114*1618Srie 		if ((error = (*fptr)(name, str, size)) == 0)
115*1618Srie 			return ((const char *)str);
116*1618Srie 	}
117*1618Srie 	return (name);
118*1618Srie }
119